一个折腾的周末

上个月有个需求让我头疼了很久。

我们团队用 Claude Code 做内部工具开发,效率确实高——写 prompt、配几个 MCP 工具,一个功能半天就搭出来了。但问题也随之而来:这东西只能在终端用

产品经理想把它集成到内部平台,让非技术的同事也能用;我想把几个常用的 Agent 封装成 API,供其他服务调用。但 Claude Code 是个 CLI 工具,强依赖终端交互,这要怎么搞?

那个周末我翻了好多资料,甚至考虑过用 expect 脚本模拟终端输入输出(别笑,真的试过),最后干脆心一横:要不自己研究一下它的内部机制,看能不能把核心能力抽出来?

摸索的过程

说干就干。我找了个开源项目 learn-claude-code,它通过拦截 Claude Code 发往 Anthropic API 的请求,分析出了 system prompt、工具定义、消息结构等参数。顺着这个思路,我搭了个简单的代理,开始观察 Claude Code 到底在干什么。

结果发现,Claude Code 的核心其实就是一个标准的 tool_use 循环,没有想象中那么神秘:

用户输入 → 构建消息 → 调 Anthropic API
    ↑___________________|
         (循环直到结束)

几个关键发现:

System Prompt 是分块的 —— 不是一个大字符串,而是 content 块数组,分身份声明、工具说明、工作流、环境注入几段。环境注入那部分(当前时间、工作目录、CLAUDE.md 内容)是每轮动态追加的。

上下文压缩是三层策略 —— 日常对话微压缩(截断旧工具结果),超过阈值时触发 LLM 摘要,完整对话会存档到 transcripts 目录。这个机制保证了长对话不会爆 token。

子代理是独立实例 —— 通过特殊工具信号派生,有自己独立的 messages 列表和工具集,运行完把结果返回给父代理。嵌套深度有限制(默认 5 层)。

搞明白这些之后,我意识到:理论上完全可以复现这套机制,然后把 CLI 外壳换掉

动手实现

接下来就是码代码的过程了。我给自己定了几个目标:

  1. 保持核心行为一致 —— 复现 Agent 循环、工具调用、子代理递归
  2. 支持多种接口 —— HTTP、SSE 流式、WebSocket 都要
  3. 保留 Claude Code 的项目级配置 —— .claude/ 那套东西很好用
  4. 支持多 Agent 编排 —— 复杂场景需要把多个 Agent 串起来

大概花了一周多时间,一个能跑通的版本出来了。给它起了个名字叫 CCServer(Claude Code Server 的缩写,虽然有点随意但好记)。

用起来怎么样

现在我的部署方式是:服务器上跑 CCServer,前端用 Gradio 做个简单界面,内部平台的其他服务直接调 HTTP 接口。

API 调用很简单:

# 创建会话
curl -X POST http://localhost:8000/sessions

# 直接对话(阻塞式)
curl -X POST http://localhost:8000/chat \
  -H "X-Session-Id: xxx" \
  -d '{"message": "分析这个目录的代码结构"}'

# 或者 SSE 流式
curl -X GET "http://localhost:8000/chat/stream?message=你好" \
  -H "X-Session-Id: xxx"

配置管理还是熟悉的 .ccserver/ 目录:

.ccserver/
├── agents/          # 自定义 subagent
├── skills/          # 技能文档
├── hooks/           # 生命周期钩子
└── settings.json    # 权限配置

格式和 Claude Code 的 .claude/ 保持一致,可以直接拷贝复用。

多 Agent 编排 是我觉得最有意思的部分。比如我做了个角色扮演对话系统,流程是这样的:

[用户输入] → [意图识别/搜索] → [话题建议] → [生成回复] → [质量检查]
                                                  ↓___________|
                                                    (不通过则重试)

每个节点都是一个完整的 Claude Agent,节点间按 DAG 执行,支持条件回边做重试。这种显式编排比单 Agent 自主调度更可控,适合业务流程固定的场景。

一些踩坑记录

  1. Prompt 兼容性 —— Claude Code 的 system prompt 结构在不同版本有变化,我实现了一个 PromptLib 系统来管理不同版本的拼接逻辑,可以通过环境变量切换。

  2. 工具调用格式 —— 要严格按照 Anthropic API 的 tool_use / tool_result 格式来,参数类型也要对齐,否则模型行为会不一致。

  3. 会话隔离 —— 每个会话要有独立的工作目录沙箱,否则文件操作会互相干扰。我用 sessions/{session_id}/workdir/ 的方式来管理。

  4. 上下文压缩阈值 —— 默认 50000 字符触发 LLM 压缩,这个值要根据实际 token 消耗调整,不同模型的换算比例不一样。

写在最后

把 CCServer 部署到服务器之后,最大的感受是:Agent 能力终于可以用起来了

以前写好的 prompt 和 MCP 配置,只能在终端里自己用。现在可以封装成接口,分享给团队,集成到各种流程里。对于一些复杂的多步骤场景,Graph 编排也让流程更清晰可控。

如果你也有类似需求——想把 Claude Code 的能力服务化、或者需要多 Agent 协作编排——可以试试看。项目已经开源(链接在文末),还在持续迭代中。

当然,这只是个学习研究性质的实现,不是官方项目,部分高级特性(比如 Claude Code 内置的那些专用 subagent)还没有完全对齐。但核心的 Agent 循环和工具系统已经挺稳定了,日常用下来没什么问题。

相关链接:

  • 项目地址:https://github.com/kazeMace/ccserver
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐