Files
knowledge-adapter-service/deploy/docker-compose.adapter.yml
姚章浩 693cd952cd feat(asset): 清理被截断的结尾图片引用,修复整单 502
仓库首次入库(此前仅存在于本地工作区与测试服构建产物中,未上传)。

改动(src/knowledge_adapter/asset_content_processor.py):
- 新增 _TRUNCATED_TRAILING_MARKDOWN_RESOURCE_IMAGE 规则,清除 chunk 末尾被截断的
  ![](resource://xxxx 残片(WeKnora 分块在图片引用中间截断时产生,旧逻辑无法匹配完整引用,
  残留 resource:// 触发 ContentProcessingError,导致整单 502)
- 回归测试 tests/test_asset_content_processor.py::
  test_truncated_trailing_markdown_resource_image_is_removed

验证证据:
- 测试服 120.76.217.51,镜像 knowledge-adapter-service:reviewed-test-aeab4b5fca2d
  (release aeab4b5fca2d8661):KB d015d05c-25c8-4d63-b2ab-e8590d3c2dfb 5 个查询全部
  http=200、records=5、残留 resource:// = 0;KB b9dacd62 无退化;容器日志无 error/exception
- 本地:pytest 141 项全通过、ruff 全通过
- 该文件与 258c31e0fe07fd08 源码的差异经逐文件 md5 比对,为唯一变更文件
2026-09-16 10:01:27 +08:00

88 lines
3.2 KiB
YAML

name: knowledge-adapter
services:
adapter:
image: "knowledge-adapter-service:${ADAPTER_IMAGE_TAG:-local}"
build:
context: ..
dockerfile: Dockerfile
user: "10001:10001"
init: true
restart: unless-stopped
read_only: true
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
pids_limit: 256
mem_limit: 1g
cpus: 2.0
tmpfs:
- /tmp:rw,noexec,nosuid,nodev,size=64m
ports:
- "127.0.0.1:18080:8080"
environment:
DIFY_KEY_HASH_CURRENT: "${DIFY_KEY_HASH_CURRENT:?set DIFY_KEY_HASH_CURRENT}"
DIFY_KEY_HASH_NEXT: "${DIFY_KEY_HASH_NEXT:-}"
WEKNORA_BASE_URL: "${WEKNORA_BASE_URL:?set WEKNORA_BASE_URL}"
WEKNORA_API_KEY_FILE: /run/secrets/weknora_api_key
WEKNORA_ALLOWED_KB_IDS: "${WEKNORA_ALLOWED_KB_IDS:?set WEKNORA_ALLOWED_KB_IDS}"
WEKNORA_TENANT_ID: "${WEKNORA_TENANT_ID:?set WEKNORA_TENANT_ID}"
WEKNORA_OSS_STORAGE_BACKEND_ID: "${WEKNORA_OSS_STORAGE_BACKEND_ID:?set WEKNORA_OSS_STORAGE_BACKEND_ID}"
OSS_REGION: "${OSS_REGION:?set OSS_REGION}"
OSS_BUCKET: "${OSS_BUCKET:?set OSS_BUCKET}"
OSS_CREDENTIAL_MODE: "${OSS_CREDENTIAL_MODE:-static_ak}"
OSS_RAM_ROLE_NAME: "${OSS_RAM_ROLE_NAME:-}"
OSS_ACCESS_KEY_ID_FILE: /run/secrets/oss_access_key_id
OSS_ACCESS_KEY_SECRET_FILE: /run/secrets/oss_access_key_secret
ASSET_PUBLIC_BASE_URL: "${ASSET_PUBLIC_BASE_URL:?set ASSET_PUBLIC_BASE_URL}"
MAX_QUERY_CHARS: "${MAX_QUERY_CHARS:-2000}"
MAX_TOP_K: "${MAX_TOP_K:-5}"
MAX_CHUNK_CHARS: "${MAX_CHUNK_CHARS:-4000}"
MAX_TOTAL_CHARS: "${MAX_TOTAL_CHARS:-12000}"
WEKNORA_TIMEOUT_SECONDS: "${WEKNORA_TIMEOUT_SECONDS:-15}"
ASSET_DATABASE_URL_FILE: /run/secrets/asset_database_url
WEKNORA_READONLY_DATABASE_URL_FILE: /run/secrets/weknora_readonly_database_url
volumes:
- type: bind
source: "${WEKNORA_API_KEY_SECRET_FILE:?set WEKNORA_API_KEY_SECRET_FILE}"
target: /run/secrets/weknora_api_key
read_only: true
- type: bind
source: "${ASSET_DATABASE_URL_SECRET_FILE:?set ASSET_DATABASE_URL_SECRET_FILE}"
target: /run/secrets/asset_database_url
read_only: true
- type: bind
source: "${WEKNORA_READONLY_DATABASE_URL_SECRET_FILE:?set WEKNORA_READONLY_DATABASE_URL_SECRET_FILE}"
target: /run/secrets/weknora_readonly_database_url
read_only: true
- type: bind
source: "${OSS_ACCESS_KEY_ID_HOST_FILE:?set OSS_ACCESS_KEY_ID_HOST_FILE}"
target: /run/secrets/oss_access_key_id
read_only: true
- type: bind
source: "${OSS_ACCESS_KEY_SECRET_HOST_FILE:?set OSS_ACCESS_KEY_SECRET_HOST_FILE}"
target: /run/secrets/oss_access_key_secret
read_only: true
healthcheck:
test:
- CMD
- python
- -c
- "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/healthz', timeout=2).read()"
interval: 10s
timeout: 3s
retries: 3
start_period: 10s
stop_grace_period: 20s
networks:
- adapter
- weknora_upstream
networks:
adapter:
driver: bridge
weknora_upstream:
external: true
name: "${WEKNORA_NETWORK_NAME:?set WEKNORA_NETWORK_NAME}"