综合实战:插件宿主 + 工具注册 + SSE 服务

专栏:TypeScript 与 Node 地基 · 第 13 / 13 篇
TypeScript综合实战

:::info 学习目标 完成本篇后你能够:独立组装一个约 200 行的微型 agent 服务,涵盖插件宿主、工具注册、agent 循环与 SSE 流式;以它为起点进入 dsh 专栏的源码精读。 前置:第 111 篇完成。预计时长:23 小时。 :::

毕业项目。四个零件、一个组装件,全部出自前十一篇:

图表(ts-capstone.md)

服务骨架(组装件)

// server.ts
import { createServer } from 'node:http'
import { MiniHost } from './mini-host'
import { chat, TOOLS, SYSTEM } from './mini_agent'

const host = new MiniHost()

// —— 插件:把工具注册进宿主(第 7 篇模式)——
const toolsPlugin = (h: MiniHost) => {
  h.provide('tools', [
    { name: 'current_time', description: '返回当前时间',
      parameters: {}, execute: async () => new Date().toISOString() },
    { name: 'word_count', description: '统计一段文字的字数',
      parameters: { text: { type: 'string' } },
      execute: async (a: { text: string }) => `共 ${a.text.length} 字` },
  ])
}
toolsPlugin(host)
const tools = host.get<{ name: string; description: string; parameters: object;
                        execute: (a: any) => Promise<string> }[]>('tools')!

agent 循环(复用第 10 篇的 chat,工具改为从宿主分发)+ SSE 端点(复用第 8 篇)组装成服务。核心增量只有一处:把工具结果以 SSE 事件推给浏览器——

res.writeHead(200, { 'content-type': 'text/event-stream', 'cache-control': 'no-cache' })
const send = (event: string, data: unknown) =>
  res.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`)

send('step', { step: 1, tool: 'word_count', args })   // 中间过程实时可见
send('done', { answer })                              // 最终答案
res.end()

这就是所有 AI 聊天界面的最小原理——中间步骤实时上屏,最终答案单独成帧。

验收标准(全部通过即毕业)

  1. curl -N -X POST localhost:3000/v1/chat -d '{"task":"现在几点了"}' 逐帧收到 stepdone 事件;
  2. 新增一个工具只需写一个插件函数,不改服务代码;
  3. Ctrl+C 后服务优雅退出(退出码 0),无悬挂定时器;
  4. (可选)给工具执行加 5 秒超时,超时返回结构化错误并继续循环。

毕业去向

  • 读生产源码:带着第 11 篇的方法论进入 DeepSeek Harness 专栏——你在第 7 篇手写的插件宿主,就是 Cordis 的最小版;第 10 篇的 mini-agent,就是 agent-loop 的最小版;本篇的服务,就是 dsh web 形态的最小版。对照着读,事半功倍
  • 继续构建:回到 Agent 工程专栏的阶段三之后(上下文工程、RAG、MCP、安全、评测),用你的 TS mini-agent 逐篇升级。

收尾

这个专栏的每一篇都刻意回答同一个问题:「dsh 为什么这么写」。当你能在读 dsh 源码时说出「这里对应我第 7 篇写过的 XX,但它多了 YY 来防 ZZ」——这个专栏的教育目标就完成了。欢迎在专栏页按顺序开跑,下一站:DeepSeek Harness

← 返回文章列表