
1. 从 Claude Code 的“泄露”说起一个精简版 Agent 到底长什么样Claude Code 能自己读文件、跑命令、改代码很多人以为背后有什么黑魔法。其实把它的行为拆开看核心就三样东西一个能理解自然语言的大模型、一组可以操作文件系统和终端的工具、以及一个不断“思考—行动—观察”的循环。这个循环就是 ReActReasoning Acting而工具调用的落地形式就是 Function Call。你完全可以用 LangChain 在几百行代码里复刻出这个骨架我把它叫做“精简版 Claude Code”。它适合谁适合已经会写 Python、想搞明白 Agent 底层到底怎么跑起来的人适合被各种 Agent 框架绕晕、想回到最小实现的人也适合手里有多个模型 Key、想统一走一个通道省去到处改配置的人。我试过把模型 endpoint 和认证文件都指向 TaoToken 的统一 Key 通道好处是换模型不用改代码只改一个环境变量。这篇文章交付三样东西一份可复制的 Agent 配置、一段工具注册代码、一次完整 ReAct 调用链的验证步骤。你跟着敲完就能在终端里输入一句“帮我看看当前目录有哪些文件”然后看着模型自己决定调用哪个工具、拿到结果、再组织成回答。整个过程没有魔法全是可调试的代码。先明确一个概念ReAct 不是某个库的名字而是一种提示词加循环的模式。模型先输出一段“思考”决定要不要调用工具如果要就输出一个结构化的调用请求你的代码执行工具把结果塞回对话历史模型再基于新结果继续思考。Function Call 则是把这个“结构化调用请求”标准化成 JSON让解析变得可靠。LangChain 的 AgentExecutor 把这两者串了起来你只需要定义工具和模型。我踩过的坑是一开始以为 Agent 会自动记住工具返回的内容结果发现必须把工具输出作为一条新消息追加到历史里否则模型下一轮就“失忆”了。LangChain 的 AgentExecutor 帮你做了这件事但你要理解它做了什么排障时才不会懵。2. TaoToken 前置把模型 endpoint 和 auth.json 统一到一个 Key在写 Agent 之前先把模型通道理顺。LangChain 支持很多模型提供方但如果你每个项目都硬编码不同的 base_url 和 api_key换模型时就要翻遍代码。TaoToken 提供的是一个统一的 API 通道你只需要记住三个东西Base URL、Key、Model ID。这三件套在 Claude Code、Cline、Codex 这类工具里是通用的配置逻辑在 LangChain 里也一样。先拿 Key。打开 https://taotoken.net/api-keys 登录后创建一个 API Key复制下来。注意这个 Key 只在创建时完整显示一次丢了就重新建一个。然后确认你要用的模型 ID比如claude-sonnet-4-20250514或者gpt-4o具体以控制台模型列表为准。Base URL 用https://taotoken.net/api注意这里不加任何查询参数保持干净。如果你用的是 Claude Code 或 Codex 这类命令行工具它们的配置文件通常叫auth.json或settings.json。以 Codex 的auth.json为例路径一般在~/.codex/auth.json内容结构大致是{ OPENAI_API_KEY: 你的 TaoToken Key, OPENAI_BASE_URL: https://taotoken.net/api }Claude Code 的配置在~/.claude/settings.json或项目级.claude/settings.json关键字段是env里的ANTHROPIC_BASE_URL和ANTHROPIC_AUTH_TOKEN{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: 你的 TaoToken Key, ANTHROPIC_MODEL: claude-sonnet-4-20250514 } }这两个文件的作用是一样的告诉工具“请求发到哪里、用什么身份、默认用哪个模型”。在 LangChain 里你不需要写文件直接用环境变量或参数传入即可。我建议用环境变量这样代码里不出现明文 Keyexport TAOTOKEN_API_KEY你的 TaoToken Key export TAOTOKEN_BASE_URLhttps://taotoken.net/api export TAOTOKEN_MODELclaude-sonnet-4-20250514这样配置的好处是你的 Agent 代码、Claude Code、Cline 可以共用同一套 Key 和 Base URL换模型时只改TAOTOKEN_MODEL一个变量。如果你打算长期跑编码类 Agent可以了解一下 Coding Plan它针对高频调用场景做了额度优化入口在 https://taotoken.net/coding-plan 。不过对于本文的最小实现按量调用就够了。有一点要注意Base URL 末尾不要多加/v1或斜杠LangChain 的 ChatOpenAI 或 ChatAnthropic 会自己拼接路径。如果你写成了https://taotoken.net/api/v1很可能出现 404。这个坑我在配置 Cline 时遇到过排查了半天才发现是路径重复。3. 可复制配置LangChain Agent 的模型与工具注册现在进入代码部分。先装依赖pip install langchain langchain-openai langchain-community如果你用 Anthropic 风格的模型把langchain-openai换成langchain-anthropic。下面以 OpenAI 兼容接口为例因为 TaoToken 的通道对 OpenAI 格式支持最直接。第一步初始化模型。关键参数是base_url和api_key都从环境变量读import os from langchain_openai import ChatOpenAI llm ChatOpenAI( modelos.environ[TAOTOKEN_MODEL], base_urlos.environ[TAOTOKEN_BASE_URL], api_keyos.environ[TAOTOKEN_API_KEY], temperature0, )temperature0是为了让工具调用的决策更稳定减少模型“自由发挥”导致不调用工具的情况。第二步定义工具。精简版 Claude Code 至少需要三个工具列目录、读文件、写文件。用 LangChain 的tool装饰器函数签名和 docstring 会被自动转成 Function Call 的 schemafrom langchain_core.tools import tool import os tool def list_files(directory: str .) - str: 列出指定目录下的文件和子目录。directory 默认为当前目录。 try: entries os.listdir(directory) return \n.join(entries) if entries else (空目录) except Exception as e: return f错误: {e} tool def read_file(path: str) - str: 读取指定路径的文本文件内容。path 是文件路径。 try: with open(path, r, encodingutf-8) as f: return f.read()[:4000] except Exception as e: return f错误: {e} tool def write_file(path: str, content: str) - str: 把 content 写入 path 指定的文件覆盖原内容。 try: with open(path, w, encodingutf-8) as f: f.write(content) return f已写入 {path}共 {len(content)} 字符 except Exception as e: return f错误: {e} tools [list_files, read_file, write_file]注意 docstring 必须写清楚参数含义模型就是靠这段文字决定怎么填参数的。我试过把 docstring 写成“读取文件”结果模型经常不传 path 参数改成“path 是文件路径”之后就正常了。第三步组装 Agent。用create_tool_calling_agent加AgentExecutorfrom langchain.agents import AgentExecutor, create_tool_calling_agent from langchain_core.prompts import ChatPromptTemplate prompt ChatPromptTemplate.from_messages([ (system, 你是一个精简版编码助手。你可以调用工具来查看和修改文件。 每次只调用一个工具拿到结果后再决定下一步。 任务完成后用中文总结你做了什么。), (human, {input}), (placeholder, {agent_scratchpad}), ]) agent create_tool_calling_agent(llm, tools, prompt) executor AgentExecutor(agentagent, toolstools, verboseTrue, max_iterations8)verboseTrue会打印每一步的思考和工具调用调试时非常有用。max_iterations8是防止模型陷入死循环超过就强制停止。agent_scratchpad这个占位符是 ReAct 循环的关键它会被自动填充成“思考—调用—结果”的历史记录。把上面三段拼成一个mini_cc.py配置部分就完成了。你可以先不运行检查一下环境变量是否都设置正确echo $TAOTOKEN_API_KEY echo $TAOTOKEN_BASE_URL echo $TAOTOKEN_MODEL三个都有输出再往下走。4. 验证请求跑通一次完整的 ReAct 调用链现在执行一次真实调用。在mini_cc.py末尾加上if __name__ __main__: result executor.invoke({input: 列出当前目录的文件然后读取 requirements.txt 的内容并总结}) print(result[output])运行python mini_cc.py你会看到类似这样的输出verbose 模式 Entering new AgentExecutor chain... 调用 list_files参数 {directory: .} 工具返回: mini_cc.py requirements.txt README.md 调用 read_file参数 {path: requirements.txt} 工具返回: langchain langchain-openai 任务完成。当前目录有 mini_cc.py、requirements.txt、README.md。 requirements.txt 里声明了两个依赖langchain 和 langchain-openai。 Finished chain.这条链路完整展示了 ReAct 的工作方式模型先思考“我需要知道有哪些文件”调用list_files拿到结果后思考“用户要读 requirements.txt”调用read_file拿到内容后不再调用工具直接生成总结。整个过程模型没有直接访问文件系统所有操作都是通过你注册的工具完成的这就是 Function Call 的安全边界。如果你想验证模型是否真的走了 TaoToken 通道可以在初始化 llm 后打印一下print(llm.openai_api_base)应该输出https://taotoken.net/api。如果输出的是默认的 OpenAI 地址说明环境变量没生效检查base_url参数是否被正确传入。再做一个更接近 Claude Code 的测试让 Agent 创建一个新文件。result executor.invoke({input: 创建一个 hello.py内容是打印 hello from mini claude code})verbose 输出里会看到模型调用write_file参数是path和content。执行完后检查当前目录确实多了hello.py。这一步验证了写操作的工具调用链也是通的。如果你在验证时遇到模型不调用工具、直接编造答案的情况通常是两个原因一是 docstring 不够明确模型不知道工具能干什么二是 system prompt 里没有强调“必须用工具获取信息”。把 system prompt 改成“你不知道文件内容必须调用工具查看”就能解决。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth排障部分按真实报错来。第一个高频错误是 401openai.AuthenticationError: Error code: 401 - {error: {message: Invalid API key}}原因通常是 Key 复制不完整、Key 被删除、或者环境变量没导出到当前 shell。排查顺序先echo $TAOTOKEN_API_KEY确认有值且没有多余空格再确认这个 Key 在控制台里是启用状态最后确认base_url没有写成别的地址。如果 Key 里包含特殊字符用引号包住再 export。第二个错误是local proxy failed或连接超时APIConnectionError: Connection error.这类报错说明请求根本没发出去。检查你的网络环境是否能访问https://taotoken.net/api可以用curl -I https://taotoken.net/api看返回。如果 curl 也超时说明是网络层问题不是代码问题。注意不要在任何配置里写代理地址TaoToken 的通道本身就是直连的额外加代理反而会破坏连接。第三个错误是reading choices相关KeyError: choices或者TypeError: NoneType object is not subscriptable这通常发生在模型返回格式和 LangChain 预期不一致时。比如你用了 Anthropic 的模型 ID但初始化的是ChatOpenAI返回结构就对不上。解决办法是模型 ID 和 LangChain 类要匹配OpenAI 格式的模型用ChatOpenAIAnthropic 格式的用ChatAnthropic。如果你不确定模型属于哪种格式先在模型对话页面发一条消息看返回的 JSON 结构里有没有choices字段。第四个错误是 OAuth 相关OAuth token expired or invalid如果你之前用 Claude Code 登录过官方账号它的auth.json里可能存的是 OAuth token 而不是 API Key。当你把ANTHROPIC_AUTH_TOKEN改成 TaoToken Key 后要确保没有残留的 OAuth 字段。打开~/.claude/settings.json检查env里是否只有ANTHROPIC_BASE_URL、ANTHROPIC_AUTH_TOKEN、ANTHROPIC_MODEL三项多余的oauthAccount之类字段删掉。Codex 的auth.json同理只保留OPENAI_API_KEY和OPENAI_BASE_URL。还有一个隐蔽的坑LangChain 的AgentExecutor默认handle_parsing_errorsFalse如果模型输出的 Function Call JSON 格式有误会直接抛异常。加上handle_parsing_errorsTrue可以让它把错误信息塞回给模型重试executor AgentExecutor( agentagent, toolstools, verboseTrue, max_iterations8, handle_parsing_errorsTrue )这个参数在模型能力较弱时特别有用能显著降低“格式错误导致整个链断掉”的概率。6. 把统一 Key 用在长期编码 Agent 上跑通最小实现之后你会发现真正影响体验的不是 Agent 逻辑而是模型通道的稳定性和成本。LangChain 的 AgentExecutor 每次调用都会把完整历史发给模型轮次多了 token 消耗很快。如果你打算把它当成日常编码助手建议做两件事一是给工具输出加截断比如read_file只返回前 4000 字符二是设置max_iterations避免模型在一个任务上反复调用工具。统一 Key 的价值在这里体现得很明显你的mini_cc.py、Claude Code、Cline 可以共用同一个TAOTOKEN_API_KEY换模型时只改TAOTOKEN_MODEL。比如从claude-sonnet-4-20250514换成gpt-4o代码一行不用动。如果你要验证某个模型在 Function Call 上的表现可以直接在模型对话页面手动构造工具调用请求看返回的 JSON 是否符合预期再决定要不要接进 Agent。对于长期跑的编码类 Agent按量调用可能会让成本不可控。Coding Plan 针对这种场景做了额度包入口在 https://taotoken.net/coding-plan 适合每天都要用 Agent 写代码的人。接入文档在 https://taotoken.net/doc 里面有各语言 SDK 的 Base URL 配置示例。API Key 管理在 https://taotoken.net/api-keys 建议给不同项目建不同的 Key方便排查和回收。最后留一个可扩展的点你可以在tools列表里加一个run_shell工具用subprocess执行命令这样就更接近 Claude Code 的完整体验了。但要注意执行 shell 命令有安全风险建议只在你自己的开发机上跑并且对命令做白名单过滤。Agent 的能力边界本质上是你给它注册了哪些工具。工具越强越要小心。