自托管的 Agent 服务:在服务端接入 Claude Code(Codex 在 M2 接入),通过统一的 REST + SSE API 为内部业务平台提供数据分析、资料查找、文档生成等能力,并附带一个 VS Code 风格的管理后台(含 Playground)。
设计文档见 docs/。
apps/server Fastify + SQLite 服务端(API、Run 调度、引擎适配、安全策略)
apps/admin 管理后台(Vue 3 + UnoCSS),生产环境由服务端托管在 /admin/
packages/shared 事件与 API 类型(前后端共享)
packages/client TS 客户端 SDK(会话、SSE 断线续传、交互回复、上传)
packages/chat-ui Vue 对话组件(时间线、工具卡片、审批/提问卡片、输入框),业务平台可直接复用
packages/ui-tokens 设计令牌(tokens.css)与 UnoCSS preset
skills/ 本地技能(部署到 /srv/agent-server/skills;官方技能通过后台"技能与插件"安装,不放在这里)
deploy/ 安装、运行环境、发布脚本与 systemd unit
docs/ 设计文档、ADR、调研
agent-claude 以服务账号 agentsvc 登录 Claude(一次即可);开发环境:本人终端已登录 claudedeploy/install.sh、deploy/setup-runtime.sh 创建,见 docs/design/10-deployment.md服务以专用用户 agentsvc 运行(systemd),详见 docs/design/10-deployment.md:
sudo deploy/install.sh # 首次:创建 agentsvc、目录权限、systemd 服务、agent-claude 命令
sudo deploy/setup-runtime.sh # 首次 / 依赖变化:Python、Node、系统工具
deploy/deploy.sh # 每次发布:构建、发布到 /srv/agent-server/app、重启
agent-claude # 以 agentsvc 身份打开 Claude Code,输入 /login 登录(只需一次)
后台:http://127.0.0.1:8787/admin/ ;日志:journalctl -u agent-server -f
pnpm install
pnpm dev:server # 服务端:http://127.0.0.1:8788(tsx watch,数据在 .dev-data/,使用你自己的 claude 登录态)
pnpm dev:admin # 后台:http://127.0.0.1:5173/admin/(代理到 8788)
首次启动时,如果没有设置 AGENT_SERVER_ADMIN_PASSWORD,会生成随机的后台密码并打印在日志里(只打印一次),登录后请在"设置"中修改。
| 环境变量 | 默认值 | 说明 |
|---|---|---|
AGENT_SERVER_HOST / AGENT_SERVER_PORT |
127.0.0.1 / 8787(开发脚本为 8788) |
监听地址 |
AGENT_SERVER_DATA_DIR |
生产 /srv/agent-server,开发 .dev-data/ |
数据目录 |
AGENT_SERVER_SHARED_DIR |
/srv/agent-server |
共享只读资源(runtime、skills) |
AGENT_SERVER_ADMIN_PASSWORD |
(随机生成) | 仅首次启动时使用 |
AGENT_SERVER_ADMIN_DIST |
apps/admin/dist |
后台静态资源目录 |
其余运行配置(路径、资料库、禁止项、网络白名单、并发等)都在后台"设置"和"资料库"页面管理。
pnpm build # 构建全部包(后台产物在 apps/admin/dist)
NODE_ENV=production node apps/server/dist/main.js
pnpm test # 服务端单元与集成测试(文件访问策略、API 全流程、LibreOffice 转换)
pnpm typecheck # 全部包类型检查
apps/server/scripts/ 下有两个手动验证脚本(会消耗真实额度):smoke-claude.ts 用来验证 SDK 和登录态,try-claude-adapter.ts 用来验证审批流和越权拦截。
KEY=ask_xxx # 在后台 API Keys 页面签发
SID=$(curl -s -X POST localhost:8787/v1/sessions -H "authorization: Bearer $KEY" -H 'content-type: application/json' -d '{}' | jq -r .id)
curl -s -X POST localhost:8787/v1/sessions/$SID/files -H "authorization: Bearer $KEY" -F file=@sales.xlsx
curl -s -X POST localhost:8787/v1/sessions/$SID/messages -H "authorization: Bearer $KEY" -H 'content-type: application/json' \
-d '{"text":"分析 uploads/sales.xlsx,生成一份 Word 报告"}'
curl -N localhost:8787/v1/sessions/$SID/stream -H "authorization: Bearer $KEY" # SSE 事件流
前端推荐直接使用 @agent-server/client 和 @agent-server/chat-ui:
import { AgentClient } from '@agent-server/client'
import { AgentChat, useChatSession } from '@agent-server/chat-ui'
import '@agent-server/ui-tokens/tokens.css'
const client = new AgentClient({ baseUrl: 'https://agent.example.com', apiKey: KEY })
const session = useChatSession(client, sessionId)
// <AgentChat :client="client" :session="session" />