Give Your AI Agent Hands: Implementing read_file Tool Calls in Python
A model that can request files stops guessing from training-data templates and answers from the actual project. The path-traversal guard and the two-call message flow are the minimum scaffolding for any filesystem-touching agent, and the DeepSeek reasoning_content fix is the kind of integration detail that turns a demo into something that survives a move across providers.
This step in a Python agent-building series takes a plain chat bot and gives it a real tool: read_file. The model no longer answers from memory; it issues a structured order for a file path, the Python program reads the file, and the model receives the content before replying. The restaurant metaphor frames it clearly: AI is the guest, Python is the kitchen, and the JSON Schema is the menu the guest orders from.
Three pieces make the flow work. A tool definition declares read_file with one required path parameter. A Python function validates that the resolved path stays inside the project root (blocking ../ and absolute paths), reads the file, and caps the read at 8,000 bytes. The chat layer calls the model once to get a tool call, then sends the file content back as a tool message to get the final answer. The post also flags a DeepSeek-specific bug: thinking models require reasoning_content to be passed back exactly, or the second call returns a 400.
The restaurant metaphor captures a fundamental division of labor: a language model never executes anything, it only emits structured requests; the application decides what to run. That separation is what makes tool calling a safe extension of model capabilities.
The path validation code isn't over-engineering. A model can emit a path like ../../../etc/passwd; without a guard against the project root, the agent would hand sensitive files to the model. Treating this as a lifeline is the right default for any agent that touches the filesystem.
The two-call pattern is the recurring skeleton of agent design: ask for intent, act, then feed the result back. The DeepSeek reasoning_content quirk shows that provider-specific message history rules can break this flow, so porting agents between APIs demands careful attention to what gets returned.