新闻详情

新闻详情

首页 / 资讯中心 / 详情

实战从零开始构建一个Coding Agent:Violin |得物技术

发布时间:2026/9/25 8:19:22来源:尧图网络
实战从零开始构建一个Coding Agent:Violin |得物技术
1. 从零构建 Coding Agent 的真实起点Coding Agent 这个词在过去一年里被反复提起但真正动手从零写一个的人并不多。原因很直接市面上的成品已经足够好用Claude Code、Codex、OpenCode 这些工具开箱即用为什么还要自己造轮子我的答案和 Violin 项目的作者一样——理解了 coding agent 的构建原理也就掌握了理解其他 agent 的一把钥匙。客服 agent、数据分析 agent、工作流编排 agent追根溯源都是 coding agent 的泛化变种底层都收敛到同一个循环问模型、调工具、再问。Violin 是一个用 Zig 写引擎、Python 写客户端的开源 Coding Agent 项目架构上借鉴了 Pi 的三层分离和 EventBus 事件驱动方案。它的核心模块包括 Agent Loop、模型适配层、工具系统、Session 管理、上下文压缩、资源加载和插件系统。这篇文章不会逐行复刻 Violin 的全部代码而是聚焦一件事怎么在本地跑通一个最小可用的 Coding Agent把配置骨架搭起来把模型通道接上把验证动作走完。适合谁读如果你已经用过 Claude Code 或类似工具想搞清楚它内部到底怎么运转或者你想给自己的项目加一个 agent 能力但不想从 HTTP 请求和 SSE 解析开始写起——这篇就是为你准备的。我会给出可复制的 settings.json 和 config.toml 示例说明每一步的验证方法并解释怎么通过 TaoToken 统一 Key 和 API 通道来接入模型能力避免在多个供应商之间来回切换配置。2. 前置准备TaoToken 统一模型通道在动手写 Agent Loop 之前有一个绕不开的问题模型从哪来。Violin 的设计里模型适配层把不同供应商的 API 差异封装在统一的Model.complete()接口后面Agent Loop 只认这个接口。但适配器内部仍然需要处理 base_url、api_key、请求体格式、流式协议这些细节。如果你同时接 OpenAI 和 Anthropic 两套协议光是维护两套鉴权和端点配置就够烦的。TaoToken 在这里的作用是提供一个统一的 API 通道。你不需要为每个模型供应商单独申请 Key、单独配置 base_url而是通过一个统一的入口来调用不同模型。对于 Coding Agent 这种需要频繁切换模型做对比测试的场景这一点很实用。具体操作上你需要先拿到一个 API Key。访问 TaoToken 的 API Keys 管理页面https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite创建一个新的 Key。这个 Key 会用在后续的 config.toml 和 settings.json 里。拿到 Key 之后模型调用的 base_url 统一指向https://taotoken.net/api。注意这个地址不带任何查询参数是纯粹的 API 端点。你的 Agent 在发起请求时把原本指向https://api.openai.com/v1或https://api.anthropic.com/v1的 base_url 替换成这个地址请求体格式保持不变——OpenAI 协议走 OpenAI 的格式Anthropic 协议走 Anthropic 的格式TaoToken 会根据你的请求路径和头部做路由。如果你对具体支持哪些模型、每个模型的上下文窗口和计费方式有疑问可以查看接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite。文档里列出了当前可用的模型列表和对应的协议类型这对配置模型适配器很关键。注意不要把 API Key 硬编码在代码里提交到版本库。Violin 的做法是从环境变量读取比如$OPENAI_API_KEY然后在 models.json 里引用这个变量名。你也可以用同样的方式把 TaoToken 的 Key 存到环境变量里配置文件只写变量名。3. 可复制配置骨架settings.json 与 config.toml现在进入实操部分。一个最小可用的 Coding Agent 需要三样东西模型配置、Agent 运行参数、工具定义。Violin 把这些拆成了几个文件我把它整理成两个核心配置文件你可以直接复制修改。3.1 模型配置models.jsonViolin 从~/.violin/agent/models.json加载模型配置结构如下{ providers: { taotoken-openai: { base_url: https://taotoken.net/api, api: openai-completions, api_key: $TAOTOKEN_API_KEY, models: [ { id: gpt-4o, name: GPT-4o, contextWindow: 128000, maxTokens: 4096 }, { id: deepseek-v4-flash, name: DeepSeek V4 Flash, contextWindow: 64000, maxTokens: 8192 } ] }, taotoken-anthropic: { base_url: https://taotoken.net/api, api: anthropic-messages, api_key: $TAOTOKEN_API_KEY, models: [ { id: claude-sonnet-4-20250514, name: Claude Sonnet 4, contextWindow: 200000, maxTokens: 8192 } ] } } }这里的关键字段是api它决定了适配器用哪种协议去解析请求和响应。openai-completions对应 OpenAI 的/chat/completions端点anthropic-messages对应 Anthropic 的/v1/messages端点。TaoToken 会根据你请求的路径自动路由到对应的上游你不需要改请求体格式。环境变量设置export TAOTOKEN_API_KEYsk-你的实际Key3.2 Agent 运行配置config.tomlAgent Loop 的行为参数放在 config.toml 里包括最大轮次、压缩阈值、重试策略[agent] max_turns 20 default_model gpt-4o system_prompt_file ~/.violin/agent/AGENTS.md [compaction] enabled true max_tokens 100000 keep_recent 10 summary_target_tokens 500 [retry] max_retries 3 base_delay_ms 500 retryable_errors [rate_limit, timeout, server_error] [tools] enabled [read_file, write_file, list_dir, bash, search, fetch] [server] host 127.0.0.1 port 9877max_turns是安全阀防止模型陷入无限工具循环。compaction段控制上下文压缩当估算 token 超过max_tokens时把旧消息压缩成摘要保留最近keep_recent条。retry段定义重试策略只对可重试的错误类型生效。3.3 项目规则AGENTS.md在项目根目录放一个 AGENTS.mdAgent 启动时会自动加载并注入 system prompt# 项目规则 ## 代码风格 - 使用 4 空格缩进 - 函数名用 snake_case - 提交信息用中文 ## 工具使用 - 修改文件前先读取原内容 - 执行 bash 命令时加 set -e - 不要删除 node_modules 以外的目录这个文件的作用是给 Agent 注入项目上下文让它知道当前项目的约定。Violin 的 ResourceLoader 会按优先级搜索{cwd}/AGENTS.md、{cwd}/CLAUDE.md、~/.violin/agent/AGENTS.md项目级配置优先于全局配置。4. 逐步验证从握手到工具调用配置写好了接下来验证 Agent 能不能跑通。我按 Violin 的通信协议把验证过程拆成四步。4.1 启动服务端并验证握手Violin 的服务端是一个 TCP Server客户端通过 JSON line 协议通信。启动服务端violin-server --config ~/.violin/agent/config.toml服务端监听 9877 端口后用 nc 或 Python 脚本发一个握手请求import asyncio, json async def handshake(): reader, writer await asyncio.open_connection(127.0.0.1, 9877) req {type: handshake, cwd: /home/user/myproject} writer.write((json.dumps(req) \n).encode()) await writer.drain() resp await reader.readline() print(json.loads(resp.decode())) asyncio.run(handshake())预期返回{type:models_result,models:[{id:gpt-4o,provider:taotoken-openai,label:GPT-4o}],default:gpt-4o} {type:skills_result,global_skills:[],project_skills:[]}如果返回了models_result说明模型配置加载成功TaoToken 的 Key 也被正确读取。如果返回错误检查环境变量TAOTOKEN_API_KEY是否设置以及 models.json 的路径是否正确。4.2 发送聊天请求并接收流式事件握手成功后发一个简单的聊天请求async def chat(): reader, writer await asyncio.open_connection(127.0.0.1, 9877) # 先握手 writer.write((json.dumps({type:handshake,cwd:.}) \n).encode()) await writer.drain() await reader.readline() # models_result await reader.readline() # skills_result # 发聊天请求 req {type: chat, content: 列出当前目录下的文件, model: gpt-4o} writer.write((json.dumps(req) \n).encode()) await writer.drain() # 读事件流 while True: line await reader.readline() if not line: break event json.loads(line.decode()) print(event[type], event.get(text, event.get(name, ))) if event[type] result: break asyncio.run(chat())预期看到的事件流turn_start delta 我来 delta 帮你 delta 列出 tool_start list_dir tool_end list_dir delta 当前 delta 目录 delta 下有 delta - README.md delta - src delta - config.toml turn_end result这个过程中Agent Loop 做了三件事调模型生成文本、检测到工具调用、执行list_dir工具、把结果回写给模型、模型继续生成最终回答。流式输出让客户端能实时看到进度而不是等全部生成完才显示。4.3 验证工具调用链路工具调用是 Coding Agent 的核心能力。Violin 内置了 6 个基本工具read_file、write_file、list_dir、bash、search、fetch。验证read_file工具req {type: chat, content: 读取 README.md 的前 10 行, model: gpt-4o}预期事件流中会出现{type:tool_start,name:read_file,args:{path:README.md,limit:10}} {type:tool_end,name:read_file,ok:true,output:# My Project\n...}如果tool_end的ok为false检查文件路径是否正确以及工具注册表里是否启用了read_file。config.toml 的[tools]段控制哪些工具可用。4.4 验证上下文压缩上下文压缩的验证需要构造一个长对话。连续发 20 轮聊天请求观察服务端日志中是否出现compaction相关输出violin-server --config ~/.violin/agent/config.toml --log-level debug当估算 token 超过 100000 时日志会显示[compaction] estimated tokens: 102400, threshold: 100000 [compaction] summarizing 15 old messages, keeping 10 recent [compaction] summary generated: 480 tokens压缩后Agent 会保留最近 10 条消息旧消息被替换成一条摘要。这样即使对话持续几十轮也不会因为上下文窗口溢出而丢失关键信息。5. 本篇常见错排查5.1 握手失败ConnectionRefusedError服务端没启动或者端口被占用。检查config.toml里的[server]段确认 host 和 port。如果端口被占用换一个端口或者用lsof -i :9877找到占用进程。5.2 models_result 为空models.json 路径不对或者 JSON 格式有误。Violin 默认从~/.violin/agent/models.json加载如果你放在别的位置需要在启动时指定--models参数。用jq . models.json验证 JSON 格式。5.3 模型调用返回 401API Key 没设置或已过期。检查环境变量TAOTOKEN_API_KEY是否在当前 shell 会话中生效。如果你用的是export命令确认没有拼写错误。另外注意models.json 里的api_key字段写的是$TAOTOKEN_API_KEY这是一个变量引用不是字面量。5.4 工具调用没有执行工具名拼写错误或者工具没在 config.toml 的[tools]段启用。检查tool_start事件里的name字段确认它在enabled列表里。如果工具执行报错看tool_end事件的output字段里面会有具体错误信息。5.5 流式输出中断SSE 解析出错或者网络超时。检查服务端日志中是否有stream_error。如果是网络问题在 config.toml 的[retry]段增加max_retries和base_delay_ms。另外确认 TaoToken 的 base_url 是https://taotoken.net/api不要加多余的路径后缀。5.6 上下文压缩后模型失忆压缩阈值设得太低或者keep_recent太小。默认阈值 100000 token保留最近 10 条消息。如果你的对话轮次很多但每轮内容很短可以适当降低阈值让压缩更早触发。如果压缩后模型仍然丢失关键信息检查摘要生成的质量必要时调整summary_target_tokens。6. 接入方式与后续扩展跑通最小可用 Agent 之后下一步是把它接入你的日常工作流。如果你主要用 Agent 做代码生成和调试可以通过模型对话页面https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite直接测试不同模型的表现对比它们在工具调用和代码理解上的差异。如果你打算长期用 Agent 做编码辅助或者构建更复杂的 Agent 工作流可以了解 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite。它针对高频编码场景做了优化适合需要稳定模型通道和统一计费的项目。对于需要管理多个 Key 或团队协作的场景控制台https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite提供了 Key 管理和用量查看功能。你可以为不同的 Agent 实例分配不同的 Key方便追踪每个项目的模型调用成本。回到 Violin 本身这个项目距离成熟产品还有不少坑要填buildJson 里 tools 参数还没序列化模型收不到工具定义插件系统没有权限隔离Lua 脚本能干任何事ACP 协议也没接暂时只能自己跟自己玩。但作为一个从零搭起来的 toy agent它的价值不在于交付一个商用产品而在于验证一个判断理解了 coding agent 的构建原理也就掌握了理解其他 agent 的一把钥匙。这个判断在构建过程中不断被验证。模型的统一适配、工具的注册与调度、会话的持久化与恢复、上下文的压缩与保留、插件的注入与拦截这些看似各不相干的问题底层都收敛到同一个循环问模型、调工具、再问。客服 agent 的会话管理、数据分析 agent 的工具链编排、工作流 agent 的状态机设计追根溯源都是这个循环在不同场景下的变形。剩下那些没填的坑既是项目当前的边界也是下一段探索的起点。把一个 toy 项目一路补到能真正落地过程本身就是最好的学习方式。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

潮汐表原理与应用:从海洋动力学到渔业实践 2026/9/25 8:52:31

潮汐表原理与应用:从海洋动力学到渔业实践

1. 潮汐表查询的核心价值与应用场景潮汐表对于沿海地区的渔民、航海人员、海洋工程从业者以及海钓爱好者而言,就像农民手中的农历节气表一样重要。以乳山口这个典型的黄海海域为例,这里每天会有两次涨潮和两次落潮,潮差能达到3-4米。掌握精确…

阅读更多 →
尤克里里入门指南:从零基础到弹唱速成 2026/9/25 8:52:31

尤克里里入门指南:从零基础到弹唱速成

1. 尤克里里入门:为什么选择这把四弦小吉他第一次接触尤克里里是在五年前的夏威夷旅行中。当地街头艺人用这把小巧的乐器弹奏出的欢快旋律,让我瞬间被它吸引。相比吉他,尤克里里更轻便(通常只有500-800克)、弦距更短&a…

阅读更多 →
装了 OpenClaw 却不会用?这 20 个 Skills 让你的 AI 助手聪明(TaoToken 配置篇) 2026/9/25 8:52:24

装了 OpenClaw 却不会用?这 20 个 Skills 让你的 AI 助手聪明(TaoToken 配置篇)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
JEB Pro v5.28实战:Android与WebAssembly跨平台逆向分析 2026/9/25 8:52:24

JEB Pro v5.28实战:Android与WebAssembly跨平台逆向分析

JEB Pro是我电脑里常年驻留的反编译器之一。很多做样本分析、协议还原、代码审计的朋友可能和我一样,桌面上既有jadx、Ghidra,也装着Frida和IDA,但遇到棘手样本时,最后真正能把整个分析流程串起来的,往往还是JEB Pro。…

阅读更多 →
手机镜防指纹手机镜源头厂家定制工厂,情侣款与出差便携款实力生产商 2026/9/25 8:52:18

手机镜防指纹手机镜源头厂家定制工厂,情侣款与出差便携款实力生产商

怀化市上怀品牌管理有限责任公司,简称上怀眼镜,是怀化本土经营40年的经典眼镜连锁品牌,累计服务超过10万近视用户,始终坚守科学配镜的舒适体验与视力管理的专业初心,是怀化本地集品牌镜片授权验配、视健康全周期管理、…

阅读更多 →
飞腾D2000/E2000/D3000平台U-Boot引导镜像制作与设备树配置实战 2026/9/25 8:52:18

飞腾D2000/E2000/D3000平台U-Boot引导镜像制作与设备树配置实战

很多人第一次拿到飞腾D2000的板子,都会习惯性先去翻内核、搞文件系统,结果卡在最前面的UBOOT引导阶段,串口什么输出都没有,或者内核起来一半就睡死。实际上飞腾平台的引导镜像制作,和x86那套完全不同,它既不…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉