Skip to content

feat(langchain): add support for reasoning content with new reasoning…#107

Merged
OhYee merged 6 commits into
mainfrom
support_reasoning_content
May 29, 2026
Merged

feat(langchain): add support for reasoning content with new reasoning…#107
OhYee merged 6 commits into
mainfrom
support_reasoning_content

Conversation

@penghuima
Copy link
Copy Markdown
Collaborator

… providers and integrate ChatDeepSeek model

Change-Id: I60b0bdc5837f88c554957d322273e8dbd63dc677

Thank you for creating a pull request to contribute to Serverless Devs agentrun-sdk-python code! Before you open the request please answer the following questions to help it be more easily integrated. Please check the boxes "[ ]" with "[x]" when done too.
Please select one of the PR types below to complete


Fix bugs

Bug detail

The specific manifestation of the bug or the associated issue.

Pull request tasks

  • Add test cases for the changes
  • Passed the CI test

Update docs

Reason for update

Why do you need to update your documentation?

Pull request tasks

  • Update Chinese documentation
  • Update English documentation

Add contributor

Contributed content

  • Code
  • Document

Content detail

if content_type == 'code' || content_type == 'document':
    please tell us `PR url`,like: https://github.com/Serverless-Devs/agentrun-sdk-python/pull/1
else:
    please describe your contribution in detail

Others

Reason for update

Why do you need to update your documentation?

… providers and integrate ChatDeepSeek model

Change-Id: I60b0bdc5837f88c554957d322273e8dbd63dc677
Signed-off-by: 久氢 <mapenghui.mph@alibaba-inc.com>
Copy link
Copy Markdown
Member

@OhYee OhYee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — feat(langchain): reasoning content support via ChatDeepSeek

变更概述:根据 provider 类型将模型路由到 ChatDeepSeek(支持 reasoning_content)或 ChatOpenAI。改动简洁,拆分方法清晰。以下是需要关注的点:


🔴 H1: "custom" 不应默认归入 _REASONING_PROVIDERS

_REASONING_PROVIDERS 包含 "custom",意味着所有自定义 provider 都会走 ChatDeepSeek 路径。但很多自定义 provider 是 OpenAI 兼容的,不支持 reasoning_content。这会导致用户使用自定义 OpenAI 兼容 provider 时被错误路由到 ChatDeepSeek,可能出现不兼容问题。

建议:移除 "custom",或改为检查模型是否真正支持 reasoning_content(如通过 model info 的某个字段判断)。


🟡 M1: _create_reasoning_model 使用 api_base 而非 base_url

ChatOpenAI 使用 base_url 参数,但 ChatDeepSeek 使用 api_base。请确认 ChatDeepSeek 确实接受 api_base——如果它也是 base_url,则自定义端点配置会静默失效。

🟡 M2: _create_reasoning_model 缺少 name=info.model

_create_openai_model 传了 name=info.model,但 _create_reasoning_model 没有,可能影响日志/trace 中的模型标识。

🟡 M3: 无测试覆盖

新增的 provider 路由逻辑和 ChatDeepSeek 集成没有对应的单测。建议至少测试路由分支和边界情况(unknown provider、None provider)。


建议修复 H1 后再合入。

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a routing branch in the LangChain model adapter so that "reasoning" providers are wrapped with langchain_deepseek.ChatDeepSeek (to surface reasoning_content), while everything else continues to be wrapped with langchain_openai.ChatOpenAI. The langchain-deepseek package is added to the langchain optional extra.

Changes:

  • Introduce _REASONING_PROVIDERS set and provider-based branching in LangChainModelAdapter.wrap_model().
  • Add _create_reasoning_model() (using ChatDeepSeek) and split out _create_openai_model().
  • Declare langchain-deepseek>=1.0.1 in the langchain extra in pyproject.toml.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
agentrun/integration/langchain/model_adapter.py Routes reasoning-capable providers to ChatDeepSeek, keeps others on ChatOpenAI.
pyproject.toml Adds langchain-deepseek dependency to the langchain extra.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +14 to +21
# 支持 reasoning_content 的供应商列表
_REASONING_PROVIDERS = frozenset({
"tongyi",
"custom",
"deepseek",
"zhipuai",
"moonshot",
"minimax",
Comment on lines +37 to +41
provider = (info.provider or "").lower()

if provider in _REASONING_PROVIDERS:
return self._create_reasoning_model(info)
return self._create_openai_model(info)
Comment on lines +47 to +54
return ChatDeepSeek(
model=info.model,
api_key=info.api_key,
api_base=info.base_url,
default_headers=info.headers,
stream_usage=True,
streaming=True,
)
Comment thread pyproject.toml
"langchain-openai>=1.0.0; python_version >= '3.10'",
"langchain-deepseek>=1.0.1; python_version >= '3.10'",
]

Comment on lines +43 to +54
def _create_reasoning_model(self, info: Any) -> Any:
"""创建支持 reasoning_content 的模型(使用 ChatDeepSeek)"""
from langchain_deepseek import ChatDeepSeek

return ChatDeepSeek(
model=info.model,
api_key=info.api_key,
api_base=info.base_url,
default_headers=info.headers,
stream_usage=True,
streaming=True,
)
Constraint: Reasoning exposure must follow MODEL_PARAMETER_RULES.thinking from the agent environment.

Rejected: Querying model metadata per invoke | The requirement pins behavior to agent env and would widen runtime behavior.

Confidence: high

Scope-risk: moderate

Directive: Keep protocol gating centralized so future protocol handlers do not leak reasoning when thinking is disabled.

Tested: uv run --extra server pytest tests/unittests/server -q; uv run --extra server ruff check agentrun/utils/reasoning.py agentrun/server/model.py agentrun/server/invoker.py agentrun/server/openai_protocol.py agentrun/server/agui_protocol.py scripts/smoke_reasoning_protocol.py tests/unittests/server/test_reasoning.py tests/unittests/server/test_openai_protocol.py tests/unittests/server/test_agui_protocol.py; real-model smoke with thinking=true and thinking=false for OpenAI and AG-UI

Change-Id: I3b1ae025db4c0d26631cf4b4bb8e322dec77ae18
Not-tested: Remote CI and hosted preprod endpoint
Signed-off-by: congxiao.wxx <congxiao.wxx@alibaba-inc.com>
Preserve the existing support_reasoning_content branch work while adding the protocol-level reasoning_content gate and verification surface.

Constraint: Keep PR 107 branch history intact and avoid force-pushing over existing work.

Rejected: Replace support_reasoning_content with codex/82508048-reasoning-content | would discard the existing LangChain provider change.

Confidence: high

Scope-risk: moderate

Directive: Continue to gate reasoning exposure from MODEL_PARAMETER_RULES.thinking, not model metadata.

Tested: uv run --extra server ruff check agentrun/utils/reasoning.py agentrun/server/model.py agentrun/server/invoker.py agentrun/server/openai_protocol.py agentrun/server/agui_protocol.py agentrun/integration/langchain/model_adapter.py scripts/smoke_reasoning_protocol.py tests/unittests/server/test_reasoning.py tests/unittests/server/test_openai_protocol.py tests/unittests/server/test_agui_protocol.py

Tested: uv run --extra server pytest tests/unittests/server -q

Tested: uv run --extra server --extra langchain pytest tests/unittests/integration/langchain tests/unittests/conversation_service/test_langchain_adapter.py -q

Tested: MODEL_PARAMETER_RULES='{"thinking": true}' AGENTRUN_SMOKE_INSECURE_SSL=true uv run --extra server python scripts/smoke_reasoning_protocol.py --env-file /Users/congxiao/workspace/agent-quickstart-langchain/.env --model qwen3-235b-a22b-thinking-2507 --protocol both --response-mode stream --expect-reasoning --expect-content

Tested: MODEL_PARAMETER_RULES='{"thinking": false}' AGENTRUN_SMOKE_INSECURE_SSL=true uv run --extra server python scripts/smoke_reasoning_protocol.py --env-file /Users/congxiao/workspace/agent-quickstart-langchain/.env --model qwen3-235b-a22b-thinking-2507 --protocol both --response-mode stream --expect-no-reasoning --expect-content
Signed-off-by: congxiao.wxx <congxiao.wxx@alibaba-inc.com>

Change-Id: I91a2e9f01eae198c297daf1e8d1819f4f8cf53d6
Review feedback showed that provider-based routing sent custom and other OpenAI-compatible providers through the DeepSeek LangChain integration. Restrict the DeepSeek-specific wrapper to the DeepSeek provider, preserve provider metadata from ModelService, and cover the routing boundaries in LangChain tests.

Constraint: ChatDeepSeek is provider-specific while ChatOpenAI remains the generic OpenAI-compatible path.

Rejected: Routing tongyi, zhipuai, moonshot, minimax, or custom through ChatDeepSeek | those providers are not guaranteed to follow DeepSeek integration semantics.

Confidence: high

Scope-risk: moderate

Directive: Add provider-specific LangChain wrappers only when the provider integration is explicitly supported and tested.

Tested: uv run --python 3.10 --all-extras pytest tests/unittests/integration/test_langchain.py tests/unittests/server/test_reasoning.py tests/unittests/server/test_openai_protocol.py::TestOpenAIReasoningContent tests/unittests/server/test_agui_protocol.py::TestAGUIReasoningContent

Tested: uv run --python 3.10 --all-extras make mypy-check

Tested: uv run --python 3.10 --all-extras make coverage
Signed-off-by: congxiao.wxx <congxiao.wxx@alibaba-inc.com>

Change-Id: I29d5dc26571cad77280860b8bb854bc1ad994f24
Add deterministic protocol-level tests for MODEL_PARAMETER_RULES.thinking so reasoning_content exposure is guarded in OpenAI and AG-UI outputs.

Constraint: Keep changes limited to test coverage and current e2e expectations.

Rejected: Rely only on the smoke script | it does not make the regression part of the test suite.

Confidence: high

Scope-risk: narrow

Directive: Keep reasoning_content coverage in both unit and e2e layers when changing protocol output.

Tested: uv run --extra server ruff check tests/unittests/server/test_reasoning.py tests/unittests/server/test_openai_protocol.py tests/unittests/server/test_agui_protocol.py tests/e2e/test_reasoning_protocol.py tests/e2e/integration/langchain/test_agent_invoke_methods.py

Tested: uv run --extra server pytest tests/unittests/server -q

Tested: uv run --extra server --extra langchain pytest tests/e2e/test_reasoning_protocol.py tests/e2e/integration/langchain/test_agent_invoke_methods.py -q

Tested: uv run --extra server --extra langchain pytest tests/unittests/integration/langchain tests/unittests/conversation_service/test_langchain_adapter.py -q

Tested: MODEL_PARAMETER_RULES='{"thinking": true}' AGENTRUN_SMOKE_INSECURE_SSL=true uv run --extra server python scripts/smoke_reasoning_protocol.py --env-file /Users/congxiao/workspace/agent-quickstart-langchain/.env --model qwen3-235b-a22b-thinking-2507 --protocol both --response-mode stream --expect-reasoning --expect-content

Tested: MODEL_PARAMETER_RULES='{"thinking": false}' AGENTRUN_SMOKE_INSECURE_SSL=true uv run --extra server python scripts/smoke_reasoning_protocol.py --env-file /Users/congxiao/workspace/agent-quickstart-langchain/.env --model qwen3-235b-a22b-thinking-2507 --protocol both --response-mode stream --expect-no-reasoning --expect-content
Signed-off-by: congxiao.wxx <congxiao.wxx@alibaba-inc.com>

Change-Id: Id273ba4afeb70c63aedcdba01bc31d46f2db3bd1
Constraint: GitHub e2e ignores tests/e2e/integration and filters node ids containing invoke.

Rejected: Use real ModelService, sandbox, or MemoryCollection resources | CI should verify SDK wiring without external service flakiness.

Confidence: high

Scope-risk: narrow

Directive: Keep this demo case in a GitHub e2e-collected path and avoid excluded node-id terms.

Tested: uv run --python 3.10 --all-extras pytest tests/unittests/integration/test_langchain_convert.py::TestConvertAstreamEventsFormat::test_on_chain_stream_model_command_update_text tests/e2e/test_langchain_server_demo.py -v --tb=short

Tested: uv run --python 3.10 --all-extras pytest tests/e2e/ --collect-only -q --ignore=tests/e2e/integration --ignore=tests/e2e/test_agent_ruintime.py --ignore=tests/e2e/test_workspace_id.py --ignore=tests/e2e/test_sandbox_browser.py --ignore=tests/e2e/test_sandbox_code_interpreter.py -k 'not (invoke or with_credential or model_proxy or process_get or delete_sandbox or delete_nonexistent_sandbox or connect_nonexistent or connect_sandbox_async or sandbox_lifecycle or connect_with_wrong_template or template_validation_code_interpreter_network or playwright or browser_recordings or aio_combined_workflow or browser_code_file_integration or aio_lifecycle)'

Tested: uv run --python 3.10 --all-extras make mypy-check

Tested: uv run --python 3.10 --all-extras make coverage

Change-Id: I1769d00572e34d1516fca6e3b4add452122d3c83
Not-tested: Real cloud sandbox and MemoryCollection resources are mocked in the e2e case.
Signed-off-by: congxiao.wxx <congxiao.wxx@alibaba-inc.com>
@OhYee OhYee merged commit a3e1756 into main May 29, 2026
3 checks passed
@OhYee OhYee deleted the support_reasoning_content branch May 29, 2026 09:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants