![]()
最近基于 DwarfStar 4 做了一个 MoonBit native binding: tonyfettes/ds4 。通过这层 binding,MoonBit 程序现在可以直接加载本地 GGUF 模型,创建推理 session,编码 chat prompt,采样 token,并把 DeepSeek V4 Flash 的生成结果流式输出。
DwarfStar 是 antirez(redis 作者)做的一个针对 DeepSeek V4 模型形态做深度优化的小型推理引擎。这意味着 MoonBit 程序可以在本地跑起一条完整的 LLM 推理循环:不需要把 prompt 发到远程 API,也不需要把模型能力包装成另一个外部服务。模型文件在本地,推理在本地,应用层控制流也在 MoonBit 里。
从聊天 API 到 Token Stream 和 Tool Call
很多用户熟悉 ChatGPT、Codex、Claude Code 这类聊天或 coding assistant 应用:输入一段话,模型一边思考一边流式输出;有时模型还会请求读取文件、运行命令或者调用某个工具。
从应用开发者的角度看,这通常表现为一次 API 调用:把 messages、system prompt、tool definitions 和采样参数发给模型服务,再从服务端接收一串流式事件。不同平台会把接口叫做 chat completion、responses、messages 或其他名字,但底层都离不开同一个过程:把对话转成 token 序列,然后让模型一个 token 一个 token 地继续生成。
一个典型的流程大致是这样:
应用把用户输入、系统指令、历史消息和工具说明整理成模型需要的 prompt。
tokenizer 把 prompt 切成 token id,包括普通文本 token 和模型约定的特殊 token。
推理引擎把这些 token 喂进模型,得到“下一个 token 是什么”的概率分布。
sampler 根据 temperature、top-p 等参数选择一个 token。
这个 token 被解码成文本片段,作为 stream delta 发给客户端。
刚生成的 token 再喂回模型,继续预测下一个 token。
直到遇到结束 token、stop sequence,或者应用主动停止。
所以,API 里看到的“流式输出”本质上就是 autoregressive inference 的外层包装。模型不是一次性吐出完整回答,而是不断预测下一个 token;API 服务再把这些 token 包装成更适合应用消费的事件流。
不同模型有不同的 chat template。DS4 在加载 GGUF 词表时会找到一组特殊 token,例如:
<|begin▁of▁sentence|> :对话开始。
<|User|> :接下来是用户消息。
<|Assistant|> :接下来是助手回复。
/ :控制或标记 thinking 内容。
<|end▁of▁sentence|> :生成结束。
|DSML| :DeepSeek 工具调用标记的一部分。
假设用户输入是:
Write a short haiku about MoonBit在 DS4 里,构造给模型看的 prompt 时,并不是只把这句话原样丢给模型,而是会变成类似这样的结构:
<|begin▁of▁sentence|>
You are a helpful assistant
<|User|>
Write a short haiku about MoonBit
<|Assistant|>
其中, <|begin▁of▁sentence|> 、 <|User|> 、 <|Assistant|> 、 是词表里的特殊 token,会被直接映射成对应 token id;普通文本则会经过 BPE tokenizer 切分成多个 token。如果关闭 thinking mode,DS4 会在 assistant prefix 后放入 ,相当于告诉模型直接进入回答阶段。
Tool call 也是类似的思路。模型并不会真的执行工具,它只会生成结构化意图;真正执行工具的一定是宿主程序。DeepSeek V4 的工具调用格式不是任意文本。DS4 里会查找 |DSML| 这个特殊 token,并围绕它渲染 DeepSeek 的 DSML tool call 文本,例如:
<|DSML|tool_calls>
<|DSML|invoke name="read_file">
<|DSML|parameter name="path" string="true">README.md
|DSML|parameter>
|DSML|invoke>
|DSML|tool_calls>这里需要区分两层: |DSML| 本身是词表里的特殊 token;但 <|DSML|tool_calls> 、 <|DSML|invoke ...> 、 <|DSML|parameter ...> 这些完整标签不是各自单独的特殊 token,而是由普通字符和 |DSML| 这个特殊 token 共同组成的 DSML 文本协议。模型生成这段文本后,服务端或宿主程序再把它解析成 OpenAI/Anthropic 风格的 tool call event。
如果模型在远端,这些事情通常由 API 服务帮应用包装好;如果模型在本地,就需要宿主程序自己控制 token stream、解析 tool call、执行工具并更新上下文。MoonBit 在这里扮演的就是这个宿主程序角色。
用 MoonBit 构建本地 Agent
仓库里的 cmd/ds4mbt 是一个 MoonBit coding micro agent。它基于同一层 DS4 binding,把本地 DeepSeek V4 Flash 推理接到一个简单的工具循环上。
cmd/ds4mbt 的基本循环可以概括成:
把用户任务、工作目录和工具说明写入 transcript。
调用 DS4 binding 生成一轮 assistant response。
从 response 中解析 <|DSML|tool_calls> 里的 read 、 write 、 edit 、 bash invocation。
在 MoonBit 里执行这些工具。
把 observations 追加回 transcript。
继续下一轮推理,直到模型不再发出工具调用。
它在 system prompt 里约定了四种工具,并要求模型用 DSML 输出工具调用:
<|DSML|tool_calls>
<|DSML|invoke name="read">
<|DSML|parameter name="path" string="true">relative/path
|DSML|parameter>
|DSML|invoke>
<|DSML|invoke name="bash">
<|DSML|parameter name="command" string="true">moon check --target native
|DSML|parameter>
|DSML|invoke>
|DSML|tool_calls>MoonBit 侧的工作是解析这段 DSML block,把 invocation 转成内部的工具调用,然后执行文件读取、写入、编辑或 shell 命令。工具结果会作为 observation 写回 transcript,下一轮推理时又会成为模型上下文的一部分。
这个结构很接近 coding assistant 的基本工作方式。模型不直接操作文件系统,也不直接运行命令;它只生成工具意图。MoonBit 程序负责把意图变成真实操作,并把结果反馈给模型。
使用上,可以先构建命令:
moon build cmd/ds4mbt --target native然后让本地模型执行一个工作区任务:
moon run cmd/ds4mbt --target native -- \
--model /path/to/model.gguf \
--cwd /path/to/project \
--prompt "Read the MoonBit package and explain the main entry point."这只是一个 micro agent,但它展示了关键路径:MoonBit 可以在本地掌握 token stream、chat template、session 状态和 tool call loop。模型推理是 DS4 runtime 的工作,应用编排则是 MoonBit 的工作。
展望
tonyfettes/ds4 还是一个早期 binding,后面还有不少可以继续打磨的方向。
首先是更高层的 chat / agent API。现在的接口已经能支撑 CLI 和 micro agent,但还可以继续整理成更稳定的 library surface,例如 message abstraction、streaming callback、stop condition、错误类型和长期 session 管理。
其次是 OpenAI/Anthropic 风格的本地接口。既然远程 API 可以把模型输出组织成 token stream、message delta 和 tool call event,本地 runtime 也可以提供类似的抽象。未来可以在 MoonBit 侧封装更接近这些应用模型的 API,让本地模型更容易替换远程模型服务。
第三是更提供完整的 agent runtime 或者接入现有的 agent 框架。 cmd/ds4mbt 目前是一个 micro agent,后续可以继续探索权限控制、工具隔离、并行工具调用、可恢复 transcript、结构化日志和更可靠的 tool parsing。
DeepSeek V4 Flash 可以在 MoonBit 程序里本地跑起来之后,重点就不只是“调用了一个 C runtime”,而是 MoonBit 可以成为本地模型应用的控制层:组织 token stream、管理上下文、解析 tool call、执行工具,并把这些能力组合进自己的工具链和应用里。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.