1. 最小体验与完整部署入口
第一次使用不需要先克隆部署仓库。直接启动 Harness 镜像,先体验 Web 控制台和 H2;完成后再进入下方的完整部署流程。
第一步:单容器体验 Harness
docker run -d \
--name dsh-java-web \
--restart unless-stopped \
-p 127.0.0.1:8090:8090 \
--add-host=host.docker.internal:host-gateway \
-e DEEPSEEK_BASE_URL='http://host.docker.internal:8777/v1' \
-e DEEPSEEK_API_KEY='你的模型 API Key' \
-e DEEPSEEK_DEFAULT_MODEL='glm-5.3-flash' \
-v dsh-web-data:/app/data \
-v dsh-web-storage:/app/storage \
registry.cn-hangzhou.aliyuncs.com/xfg-studio/deepseek-harness-java:0.1.6
浏览器打开 http://127.0.0.1:8090/,先进入「设置 → 模型设置 → 添加模型」,填写模型服务地址、模型名称和 API Key,保存后再新建工作区和会话,发送:请介绍一下你当前可以使用的工具,并说明哪些操作需要人工审批。
进入下一步前执行 docker rm -f dsh-java-web,避免容器名和端口冲突。
第二步:部署插件服务并安装一个 JAR
先只启动 Harness 和 MySQL 管理服务,体验一个插件,不必一次启动商城和所有组件:
git clone https://github.com/fuzhengwei/dsh-java-deploy.git
cd dsh-java-deploy
cp .env.example .env
# 编辑 .env,填写 DEEPSEEK_API_KEY
docker compose up -d dsh-java-web dsh-java-mysql
./scripts/install-plugins.sh --mysql-only
访问 http://127.0.0.1:8091/ 添加数据库连接,再用下面的命令确认插件已经激活:
curl http://127.0.0.1:8090/api/harness/plugins
在 Harness 会话中发送:请列出当前已配置的数据库连接,并说明这个插件提供哪些只读能力。
第三步:标准部署 Harness 与商城
下载并执行 标准部署脚本。脚本会拉取 Harness 与 2D Weekend Mall 镜像,使用 host 网络启动两个容器,并挂载数据、存储和插件卷:
curl -fsSLO https://dsh-java.xiaofuge.cn/scripts/deploy-standard.sh
chmod +x deploy-standard.sh
./deploy-standard.sh
启动后访问:
http://127.0.0.1:8090 # Harness Web
http://127.0.0.1:8091 # DSH MySQL
http://127.0.0.1:18080 # 2D Weekend Mall
部署完成后打开 Harness,进入「设置 → 模型设置 → 添加模型」,填写模型服务地址、模型名称和 API Key,保存后即可开始对话。
验证插件:
curl http://127.0.0.1:8090/api/harness/plugins
http://127.0.0.1:8090,进入“设置 → 插件管理 → 选择 JAR”,上传后点击“安装并启用”。http://127.0.0.1:8090/api/harness/plugins,确认 mall-weekend-assistant 已激活;商城访问地址为 http://127.0.0.1:18080。2. 使用 Web 控制台
启动完成后,在浏览器打开:
http://localhost:8090/
- 新建或选择一个工作区,用于隔离文件操作和运行上下文。
- 创建 Agent 会话,左侧可切换、恢复或删除会话。
- 进入模型设置,确认默认 provider、model 与 API Key。
- 发送第一条消息,观察 SSE 流式输出和工具卡片。
- 需要人工确认时,在审批面板批准或拒绝任务。
- 打开插件页面,安装、启用、停用或配置插件。
控制台原生实现了 Markdown 渲染、代码高亮、DOMPurify XSS 净化、历史会话回放、轨迹视图、插件启停与审批处理。
2.1 用 API 发起第一条消息
阻塞式接口适合脚本测试;SSE 接口适合观察流式行为:
curl -X POST http://localhost:8090/api/agent/message \
-H 'Content-Type: application/json' \
-d '{
"agentId": "local-agent",
"message": "Hello!",
"provider": "deepseek",
"model": "gpt-5.5",
"maxTokens": 8192,
"cwd": "."
}'
curl -N -X POST http://localhost:8090/api/agent/stream \
-H 'Content-Type: application/json' \
-d '{"agentId": "local-agent", "message": "介绍这个项目的架构"}'
harness.auth.api-keys,请求需额外携带 X-API-Key: your-api-key 或 Authorization: Bearer your-api-key。3. 完整商城案例:2D Weekend Mall
2D Weekend Mall 是完整部署阶段的 PC 虚拟商城,商品、购物车、订单、支付和物流在浏览器闭环。使用标准部署脚本即可启动 Harness 与商城服务,再通过 Harness 插件管理安装客服插件 JAR。
推荐:执行标准部署脚本
curl -fsSLO https://dsh-java.xiaofuge.cn/scripts/deploy-standard.sh
chmod +x deploy-standard.sh
./deploy-standard.sh
打开 http://127.0.0.1:18080/ 访问商城;然后从 GitHub 下载 mall-agent-plugin-1.0.0-SNAPSHOT.jar,在 http://127.0.0.1:8090 的“设置 → 插件管理”中选择 JAR、安装并启用。插件配置使用 mall.base-url=http://127.0.0.1:18080,服务令牌使用脚本输出的值。
源码开发时启动商城
只有需要修改商城源码时才使用下面的本地启动方式;普通部署请使用上面的标准部署脚本。
git clone https://github.com/fuzhengwei/2d-weekend-mall.git
cd 2d-weekend-mall
mvn -pl mall-app spring-boot:run
打开 http://localhost:18080,默认演示用户是 customer-1。
构建并安装客服插件
mvn package
JAR="$PWD/mall-agent-plugin/target/mall-agent-plugin-1.0.0-SNAPSHOT.jar"
curl -X POST http://localhost:8090/api/harness/plugins/install \
-H 'Content-Type: application/json' \
-d "{
\"pluginId\": \"mall-weekend-assistant\",
\"displayName\": \"2D Weekend Mall Assistant\",
\"pluginVersion\": \"1.0.0\",
\"runtimeType\": \"JAVA_NATIVE\",
\"sourcePath\": \"$JAR\",
\"entrypoint\": \"mall-agent-plugin-1.0.0-SNAPSHOT.jar\"
}"
curl -X POST http://localhost:8090/api/harness/plugins/run \
-H 'Content-Type: application/json' \
-d '{"pluginId":"mall-weekend-assistant"}'
配置商城凭证
- 在 Harness 插件配置中设置
mall.service-token,与商城mall.security.service-token一致。 - 建议设置
mall.base-url为http://127.0.0.1:18080。 - 保存后停用并重新启用插件,确保重新执行
configure(context)。
安装成功后,Agent 会看到 plugin__mall-weekend-assistant__search_products 等工具,可以搜索商品、查询订单和物流。
4. 插件服务:dsh-java-mysql
这个案例提供 MySQL 管理后台与 AI 助手。部署体验优先使用 dsh-java-deploy 的预构建 JAR,只启动两个服务并安装一个插件;需要修改源码时,再使用下面的本地构建方式。
推荐:只启动服务并安装插件
cd dsh-java-deploy
docker compose up -d dsh-java-web dsh-java-mysql
./scripts/install-plugins.sh --mysql-only
curl http://127.0.0.1:8090/api/harness/plugins
启动管理后台
git clone https://github.com/fuzhengwei/dsh-java-mysql.git
cd dsh-java-mysql
mvn clean package
java -jar dsh-java-mysql-app/target/dsh-java-mysql-app-*.jar
打开 http://localhost:8091,添加数据库连接后即可浏览表、执行 SQL 和查看 AI 分析。
安装 MySQL 插件
JAR="$PWD/dsh-java-mysql-plugin/target/dsh-java-mysql-plugin-0.1.0-SNAPSHOT.jar"
curl -X POST http://localhost:8090/api/harness/plugins/install \
-H 'Content-Type: application/json' \
-d "{\"pluginId\":\"dsh-java-mysql-plugin\",\"displayName\":\"DSH MySQL Plugin\",\"pluginVersion\":\"0.1.0\",\"runtimeType\":\"JAVA_NATIVE\",\"sourcePath\":\"$JAR\",\"entrypoint\":\"dsh-java-mysql-plugin-0.1.0-SNAPSHOT.jar\"}"
curl -X POST http://localhost:8090/api/harness/plugins/activate \
-H 'Content-Type: application/json' \
-d '{"pluginId":"dsh-java-mysql-plugin"}'
| 工具 | 能力 |
|---|---|
| mysql_list_connections | 列出本地已配置连接 |
| mysql_read_query | 执行 SELECT、SHOW、DESC 等只读查询 |
| mysql_explain_query | 获取 SQL 执行计划 |
| mysql_performance_snapshot | 查看性能快照 |
| mysql_sql_review | 本地 SQL 风险审计,不连库 |
5. 插件开发教程 · SPI 与 AI Prompt
插件先选择合适的运行模式,再实现 SPI 契约并注册工具。当前工程版本为 v0.1.6,Java Native Plugin 只依赖 deepseek-harness-java-types,可用 archetype 生成骨架,再用安装脚本验证。
用 v0.1.6 Archetype 生成工程
cd /path/to/deepseek-harness-java
mvn -q -pl deepseek-harness-java-types install -DskipTests
mvn -q -pl plugins/deepseek-harness-plugin-archetype install -DskipTests
mvn archetype:generate \
-DarchetypeGroupId=cn.xiaofuge \
-DarchetypeArtifactId=deepseek-harness-plugin-archetype \
-DarchetypeVersion=0.1.6 \
-DgroupId=com.acme -DartifactId=acme-weather-plugin \
-Dversion=1.0.0-SNAPSHOT -Dpackage=com.acme.weather \
-DpluginId=acme-weather -DpluginName="Acme Weather Plugin" \
-DpluginClass=WeatherPlugin -DinteractiveMode=false
JAR 必须包含 META-INF/plugin.yaml 和 META-INF/services/cn.xiaofuge.deepseek.harness.domain.spi.JavaHarnessPlugin。工具最终以 plugin__<pluginId>__<toolName> 的名称提供给 Agent。
打包并安装验证
cd acme-weather-plugin
mvn package
bash /path/to/deepseek-harness-java/scripts/install-plugin.sh \
--jar target/acme-weather-plugin-1.0.0-SNAPSHOT.jar \
--host http://127.0.0.1:8090
| 模式 | 适用场景 |
|---|---|
| Java Native | Java 工具、数据库/业务 API、低延迟进程内调用,使用 URLClassLoader 隔离。 |
| Node Bridge | 复用 Node 生态,sidecar 进程以 JSON-RPC 与宿主通信。 |
| MCP stdio | 已有 MCP Server 能力接入,适合标准化工具生态。 |
最小 Java 插件结构
your-plugin/
├── pom.xml
└── src/main/
├── java/cn/xiaofuge/plugin/
│ ├── YourPlugin.java
│ └── YourTool.java
└── resources/META-INF/
├── plugin.yaml
└── services/cn.xiaofuge.deepseek.harness.domain.spi.JavaHarnessPlugin
宿主加载后会解析 plugin.yaml,创建插件实例,注册工具并进入生命周期管理;Agent 只能调用注册成功的工具。
AI Prompt 1 · 需求到插件设计
你是一名 Java Agent 插件架构师。请把下面的需求整理成 DSH Java Java Native 插件设计文档:
业务需求:【在这里粘贴需求】
输出要求:
1. 插件 ID、显示名、版本、运行时类型。
2. 工具清单:工具名、用途、输入参数、返回结构、异常分支。
3. 每个工具的风险等级:只读 / 写操作 / 高危操作。
4. 需要外部配置的 key、默认值和校验规则。
5. 下载/调用边界:允许访问的域名、超时、重试、审计点。
6. 用表格列出实现文件、职责和依赖方向。
AI Prompt 2 · 生成 Maven + SPI 骨架
请根据下面的插件设计文档,生成一个可编译的 DSH Java Java Native 插件骨架:
插件名:【your-plugin】
基础包名:【cn.xiaofuge.plugin】
Java 版本:17
输出要求:
1. pom.xml:不引入 Spring 容器,最小依赖。
2. plugin.yaml:包含 pluginId、displayName、pluginVersion、runtimeType、entrypoint。
3. JavaHarnessPlugin SPI 服务声明文件。
4. YourPlugin 类:初始化、configure、start、stop 生命周期。
5. YourTool 类:返回 ToolDefinition,实现 execute。
6. 只输出文件,不要解释。文件路径注释放在每个文件块顶部。
AI Prompt 3 · 生成业务工具实现
请实现 Java Native 插件工具:
工具名:【your_tool】
功能:【查询业务数据 / 调用业务 API / 读取本地资源】
输入参数:【参数名、类型、是否必填、校验规则】
返回要求:【字段、示例、空结果结构】
异常要求:【超时、认证失败、业务失败】
实现要求:
1. 不使用 Spring 注解,只依赖 SPI 和标准库。
2. 输入必须校验,错误信息给 Agent 可读的结构。
3. 外部 HTTP 请求要设置超时、失败分类和日志脱敏。
4. 只做指定能力,不额外扩展写操作。
5. 返回 Java 原生 Map/List/String,避免序列化到 UI 的副作用。
AI Prompt 4 · 打包、安装与验证
请根据当前插件项目生成验证文档:
插件路径:【/absolute/path/to/your-plugin.jar】
插件 ID:【your-plugin】
Harness 地址:【http://localhost:8090】
输出要求:
1. mvn clean package 命令。
2. /api/harness/plugins/install curl 命令。
3. 插件启动或激活 curl 命令。
4. 3 个能证明工具生效的 Agent Prompt。
5. 3 个应触发错误分支的测试用例。
6. 安装失败时的日志检查清单。
6. 发布插件到社区收录
插件开发完成并本地验证通过后,可以发布到 GitHub 与社区共享。社区通过 GitHub topic 统一收录插件——只要给仓库添加 dsh-plugin-java 标签,就会出现在 github.com/topics/dsh-plugin-java 主题页,被其他开发者发现。
发布步骤
- 把插件源码推送到一个公开的 GitHub 仓库。
- 完善 README:插件能力、工具清单、安装命令、配置项和截图。
- 建议附上构建好的 JAR(Release 附件或明确的构建命令)。
- 给仓库添加
dsh-plugin-java标签(topic),等待被社区收录。
添加收录标签
方式一:打开仓库主页,点击右上角 About 区域的设置图标,在 Topics 输入框中添加 dsh-plugin-java 并保存。
方式二:使用 GitHub CLI 一行完成:
gh repo edit --add-topic dsh-plugin-java
dsh-java- 为前缀(如 dsh-java-mysql),README 首屏写清「这是一个 DSH Java 插件」,方便检索与识别。7. 持久化部署与安全
完整部署推荐使用 标准部署脚本。脚本使用 Harness 0.1.6.4 与商城 0.1.1 镜像,并创建持久化数据、存储和插件卷:
curl -fsSLO https://dsh-java.xiaofuge.cn/scripts/deploy-standard.sh
chmod +x deploy-standard.sh
./deploy-standard.sh
脚本部署完成后,请从 GitHub 下载商城插件 JAR,在 Harness 的“设置 → 插件管理”中选择 JAR、安装并启用。脚本会输出相同的下载地址、服务地址和商城服务令牌。
.env 关键配置项
| 变量 | 说明 | 建议 |
|---|---|---|
MALL_SERVICE_TOKEN | 商城与 Mall 插件之间的服务凭证 | 改成随机值,两边必须一致 |
DEEPSEEK_BASE_URL | Harness 调用 LLM 的网关地址 | 容器内访问宿主机用 http://host.docker.internal:8777/v1 |
DEEPSEEK_API_KEY | 模型 API Key | 必填,否则对话无输出 |
DEEPSEEK_DEFAULT_MODEL | 默认模型 | 如 glm-5.3-flash |
HARNESS_PLUGIN_API_TOKEN | 插件接口写请求令牌 | 暴露到非本机网络时必配 |
127.0.0.1 只指向容器自身,不是宿主机也不是 dsh-java-web。部署包已通过 Docker DNS 解决——dsh-java-mysql:8091、2d-weekend-mall:18080、dsh-java-web:8090 互相用容器名访问,无需修改任何业务代码。本地构建
git clone https://gitcode.net/KnowledgePlanet/deepseek-harness-java.git
cd deepseek-harness-java
mvn clean package -DskipTests
java -jar deepseek-harness-java-app/target/deepseek-harness-java-app-1.0.0-SNAPSHOT.jar \
--spring.profiles.active=standalone
standalone profile 使用 H2 文件库,无需 MySQL。默认 profile 需要导入 MySQL 表并配置 SPRING_DATASOURCE_URL、SPRING_DATASOURCE_USERNAME、SPRING_DATASOURCE_PASSWORD。
安全检查
- 不要把 API Key 提交进仓库或写入公共镜像。
- 生产环境启用 API Key、HTTPS、访问日志和最小化网络暴露。
- Shell、写文件、插件和子进程默认属于高风险操作,保留人工审批。
- 公开部署时补充限流、审计、备份与集中观测。
- 当前定位是单实例 Agent 运行时,分布式多租户需自行扩展协调与隔离策略。
8. MySQL 库表导入与数据源配置
默认 profile 使用 MySQL 作为事件溯源与配置存储。建库脚本位于 deepseek-harness-java 仓库 docs/dev-ops/mysql/sql/deepseek_harness_java.sql,包含 12 张表与初始工具/模型配置数据。
1)导入建库脚本
脚本内含 CREATE DATABASE IF NOT EXISTS deepseek_harness_java 与全部建表语句,直接执行即可(重复执行会先 DROP 再建,注意备份):
mysql -h 127.0.0.1 -P 3306 -u root -p < docs/dev-ops/mysql/sql/deepseek_harness_java.sql
2)配置数据源环境变量
export SPRING_DATASOURCE_URL='jdbc:mysql://127.0.0.1:3306/deepseek_harness_java?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true'
export SPRING_DATASOURCE_USERNAME='root'
export SPRING_DATASOURCE_PASSWORD='your-password'
Docker 容器内访问宿主机 MySQL:把 127.0.0.1 换成 host.docker.internal(Mac/Windows)或宿主机内网 IP(Linux)。
3)启动应用(默认 profile)
java -jar deepseek-harness-java-app/target/deepseek-harness-java-app-1.0.0-SNAPSHOT.jar
不加 --spring.profiles.active=standalone 即走 MySQL。首次启动会自动执行内嵌 schema.sql 补全缺失的表(幂等,可重复启动)。
12 张核心表与导入验证
harness_session_event_log:会话事件日志(事件溯源核心)harness_goal_state:任务目标状态harness_model_setting:模型配置(预置初始数据)harness_plugin_config:插件配置- 其余覆盖任务、审批、工具与工作区投影
导入后验证:SHOW TABLES; 应有 12 张 harness_* 表;harness_model_setting 已有预置 provider/model 行。判断 MySQL 是否在跑用 nc -z 127.0.0.1 3306,别依赖进程列表。
schema.sql 使用 INSERT ... WHERE NOT EXISTS 只插不更——已存在的配置行(如模型设置)不会被覆盖。下线旧模型或更新配置时需手动 UPDATE;修改已有表结构时不要只改 CREATE TABLE,应引入可重复执行的迁移脚本或 Flyway/Liquibase。9. H2 还是 MySQL
两套数据源共用同一 schema,通过 profile 一键切换,不需要改代码:
| 维度 | H2(standalone profile) | MySQL(默认 profile) |
|---|---|---|
| 部署 | 零依赖,文件库 ./data/*.mv.db | 需独立 MySQL 实例 + 导入建库脚本 |
| 兼容性 | MODE=MySQL 兼容模式,共用同一 schema | 原生 |
| 适用 | 本地开发、演示、单机轻量使用 | 生产、联调、长期持久化 |
| 风险 | 文件锁、并发能力有限 | 需运维:备份、连接池、监控 |
java -jar deepseek-harness-java-app-*.jar --spring.profiles.active=standalone。生产环境请勿使用 H2——本项目曾真实发生过「容器沙箱里 lsof/ps 看不到跨用户 MySQL 进程,误判没跑而切了 H2,结果应用连 H2、界面看的是 MySQL,两边数据对不上」的事故。10. 上线前检查清单
把 Harness 部署到服务器或企业内部环境前,逐项确认:
安全
- 配置
harness.auth.api-keys(为空则全放行) - 模型 API Key 走环境变量,绝不硬编码提交仓库
- 确认审批覆盖 Shell / 写文件 / 插件 / 子进程
- 服务不直接暴露公网,前置网关
稳定性
- 外部 MySQL + 连接池 + 备份 + 事件表归档策略
- 评估沙箱模式,生产可从 READ_ONLY 起步
- 关注无界线程池,必要时改有界
- 当前为单实例设计,多实例需自行扩展协调
11. 常见问题
访问 8090 打不开?
先用 docker logs -f dsh-java-web 查看启动日志;确认端口没有被占用,并检查宿主机防火墙或安全组规则。
容器之间 Connection refused?
确认三个服务都使用 dsh-net,并使用 dsh-java-web、dsh-java-mysql、2d-weekend-mall 这类容器名,不要在容器内写 127.0.0.1。
对话没有模型输出?
检查 DEEPSEEK_BASE_URL 和 DEEPSEEK_API_KEY。如果使用私有 OpenAI 兼容网关,地址需包含 /v1。
插件启动后 Agent 看不到工具?
检查 plugin.yaml、SPI 服务声明和 JAR 路径。修改插件配置后应停用并重新启用,让插件重新执行 configure(context)。
发布的插件没有被社区收录?
确认仓库是公开仓库,且 topic 名称完全是 dsh-plugin-java(GitHub topic 只允许小写字母、数字和连字符)。添加后稍等片刻即可在主题页看到。
Mall 插件 401/403?
确认插件配置 mall.service-token 与商城容器 MALL_SERVICE_TOKEN 一致,并检查插件里的 mall.base-url。
插件配置保存后没生效?
停用再激活插件,让插件重新执行 configure()。非 127.0.0.1 的插件写请求必须携带 X-Plugin-Api-Token。
