From 7259dc27fe55f452d243b151939bb3437040d689 Mon Sep 17 00:00:00 2001 From: "J.Jason" <130959319+JJasonSun@users.noreply.github.com> Date: Sat, 12 Sep 2026 15:18:08 +0800 Subject: [PATCH 1/4] Refactor ECNU skill around practical integration and targeted diagnosis Replace the broad default workflow with a working connection, official-doc routing, and focused ECNU recipes. Preserve diagnostic scripts, tests, and dated evidence. Add a local continuation plan without introducing a benchmark framework. --- AGENTS.md | 54 ++- README.md | 230 +++---------- SKILL.md | 321 +++++------------- docs/skill-refactor-plan.md | 88 +++++ references/api_reference.md | 455 ++----------------------- references/examples.md | 657 ++++-------------------------------- references/models.md | 300 ++-------------- references/workflows.md | 396 ++++------------------ 8 files changed, 443 insertions(+), 2058 deletions(-) create mode 100644 docs/skill-refactor-plan.md diff --git a/AGENTS.md b/AGENTS.md index b846f41..93de1a7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,49 +2,43 @@ ## Purpose -This repository is an Agent Skills package for the ECNU LLM Open Platform API. -The repository content is the skill; there is no production application. +This is an Agent Skills package, not a production application. +Optimize for less repeated setup, lookup, and troubleshooting work. +These instructions apply to maintaining this repository, not consuming apps. ## File routing -- `SKILL.md` is the concise task entry point. -- `references/api_reference.md` contains documented endpoint contracts. -- Model selection and Agent design: `references/models.md` and `references/agent_development.md`. -- `references/examples.md` contains minimal safe examples. -- `references/workflows.md` contains executable integration and test flows. -- `references/known_deviations.md` contains dated live observations only. -- `scripts/smoke_test.py` performs opt-in live structural checks. -- `scripts/validate_skill.py` and `tests/` provide offline validation. +- `SKILL.md`: small integration entry point and task routing. +- `references/api_reference.md`: official endpoint links, not copied field tables. +- `references/models.md`: selection defaults and current account-source pointers. +- `references/examples.md`: ECNU-specific integration recipes. +- `references/workflows.md`: symptom-driven, opt-in diagnostics. +- `references/known_deviations.md`: dated live evidence; preserve dates and scope. +- `references/agent_development.md`: historical guidance cited by old observations. +- `scripts/` and `tests/`: existing diagnostics and offline validation. +- `docs/skill-refactor-plan.md`: scope, local handoff, and acceptance checks. ## Editing rules -- Treat current official ECNU documentation as the documented contract. -- Keep documented facts, live observations, application policy, and unverified - claims distinct. -- Do not invent undocumented fields, limits, model capabilities, or prices. -- Put point-in-time behavior only in `known_deviations.md` with dated evidence. -- Keep examples sequential, timeout-bounded, and environment-key based. -- Maintain this repository with Git; update the deployed skill via `npx skills update -g ecnu-api`, never by manually copying it. +- Prefer current official contracts; keep observed differences separately dated. +- Add content only when it saves a concrete lookup, decision, mistake, or repeated action. +- Keep everyday integration separate from platform audits and repository maintenance. +- Do not invent API limits or copy upstream model defaults into ECNU requests. +- Do not refresh a test date or label a snippet live-verified without a real test. +- Update installed copies via `npx skills update -g ecnu-api`, not manual copying. ## Validation -Run before committing: - ```bash python3 scripts/validate_skill.py python3 -m unittest discover -s tests -v python3 -m compileall scripts tests uvx --from skills-ref agentskills validate "$PWD" +git diff --check ``` -Review `git diff --check` and scan tracked content for secrets and personal paths. - -## Safety - -- Read live credentials only from `ECNU_API_KEY`; never accept a CLI key. -- Never commit keys, Authorization values, private inputs, raw responses, - generated media, one-time URLs, or full reasoning content. -- Keep API calls serial and enforce the declared credit ceiling. -- Do not automatically retry POST requests after ambiguous transport failures. -- Record only sanitized response structure and allowlisted diagnostic headers. -- Do not update an observation date unless the behavior was reproduced. +Report unavailable checks as not run. Review tracked changes for secrets. +Live checks use only `ECNU_API_KEY`, serial requests, no ambiguous POST retry, +and an approved cumulative budget. Never commit private inputs, reasoning, +credentials, generated media, one-time URLs, or raw responses. Keep sanitized +live artifacts under the ignored `.live-artifacts/` directory. diff --git a/README.md b/README.md index 7c4ad6b..7740ab7 100644 --- a/README.md +++ b/README.md @@ -1,209 +1,67 @@ # ECNU API Agent Skill -Unofficial community [Agent Skill](https://agentskills.io/) for implementing, -reviewing, testing, and troubleshooting integrations with the ECNU / ChatECNU -LLM Open Platform API. +An unofficial skill that helps an Agent connect to the ECNU / ChatECNU LLM +Open Platform without repeatedly finding the same docs or rediscovering the +same integration differences. -The skill covers: +The default path is small: a working connection example, task-specific official +documentation, and a few ECNU-specific recipes. Full live diagnostics are opt-in. +This is not another API manual, a generic Agent course, or a required test harness. -- OpenAI-compatible Chat Completions and Responses APIs -- vision and multimodal messages -- embeddings and rerank -- image generation and text-to-speech -- structured output -- Anthropic-compatible API usage -- URL-parameter ChatECNU links -- model selection, authentication, quotas, errors, and known service deviations -- upstream Qwen3.8, DeepSeek, and DSpark context, distinct from ECNU guarantees -- Agent prompt templates, tool continuation, context management, and evaluation - -## Install +## Install and use ```bash npx skills add JJasonSun/ecnu-api ``` -Use the skills CLI to manage installed copies. For an existing global -installation, update from its upstream source with: - -```bash -npx skills update -g ecnu-api -``` - -Maintain this source repository with Git; do not deploy edits by manually -copying files into an installed skill directory. - -Example invocation: - -```text -Use $ecnu-api to review this ECNU API integration. -``` - -## Repository layout +Example request: ```text -ecnu-api/ -├── SKILL.md -├── AGENTS.md -├── references/ -│ ├── api_reference.md -│ ├── models.md -│ ├── agent_development.md -│ ├── examples.md -│ ├── workflows.md -│ └── known_deviations.md -├── scripts/ -│ ├── smoke_test.py -│ └── validate_skill.py -├── tests/ -│ ├── test_repository_contracts.py -│ └── test_smoke_test.py -└── .github/workflows/validate.yml +Use $ecnu-api to adapt this application to ECNU. Keep the current framework. +Only change the integration and its relevant checks; do not make live requests. ``` -`SKILL.md` contains the core workflow and tells an agent when to load each -focused reference. Live observations are isolated from documented contracts in -`references/known_deviations.md`. - -For Agent development, start with -[model-specific prompt and tool guidance](references/agent_development.md). -It covers ECNU's differences from upstream DeepSeek-V4.1 and Qwen3.8, -reusable task prompts, thinking/tool history, and checks for actual task success. - -## Configure a key safely - -Store the key in an environment variable. Do not put it in source files, shell -scripts, screenshots, committed reports, or chat prompts. - -PowerShell: - -```powershell -$env:ECNU_API_KEY = "your-api-key" -``` - -macOS or Linux: +For an existing global installation: ```bash -export ECNU_API_KEY="your-api-key" +npx skills update -g ecnu-api ``` -A key pasted into a chat or public location should be revoked or rotated after -testing. +Configure `ECNU_API_KEY` through the local environment or secret manager when +execution is needed. Never paste a real key into chat or commit it. Missing +credentials should not prevent the Agent from writing or reviewing code. -## Reproducible live validation +## Where to go -The runner reads only `ECNU_API_KEY`, sends requests serially, and does not -retry POST requests. Select the smallest profile that answers the question: - -| Profile | Scope | +| Need | Resource | |---|---| -| `auth` | Service status plus valid, invalid, and missing-token model discovery; no billable POST requests. This is the default. | -| `core` | Low-cost Chat Completions, Responses, embeddings, rerank, vision, structured output, error-shape, OpenAI SDK, and LangChain probes. | -| `compatibility` | Responses vision and Anthropic-compatible models, aliases, effort controls, long-context suffix behavior, vision, and SDK probes. | -| `billable` | Fixed-price TTS and one documented image-generation probe, subject to the credit ceiling. | -| `all` | The union of all four profiles; later billable cases are skipped when the ceiling is reached. | - -Examples: - -```bash -python3 scripts/smoke_test.py --profile auth --max-credits 0 --output .live-artifacts/auth.json -python3 scripts/smoke_test.py --profile core --max-credits 50 --output .live-artifacts/core.json -python3 scripts/smoke_test.py --profile compatibility --max-credits 50 --output .live-artifacts/compatibility.json -python3 scripts/smoke_test.py --profile billable --max-credits 50 --output .live-artifacts/billable.json -python3 scripts/smoke_test.py --profile all --max-credits 50 --output .live-artifacts/all.json -``` - -`--max-credits` is a conservative planned-cost gate, defaulting to 50. The -runner reserves each case's estimate before sending it and skips a case that -would exceed the ceiling. The estimate is not proof of the service's actual -debit. Recheck the official quota and pricing page before a live run. - -Use `--case` to rerun only named cases within the selected profile; repeat the -flag to select more than one: - -```bash -python3 scripts/smoke_test.py --profile core --case openai_sdk_chat \ - --max-credits 1 --output .live-artifacts/openai-sdk-chat.json -``` - -Keep reports under `.live-artifacts/`, which is Git-ignored. Reports contain -statuses and structural summaries, not the API key, generated content, -reasoning text, media, or one-time URLs. - -Selected SDK probes on 2026-08-23 passed with OpenAI Python SDK 2.48.0, -Anthropic Python SDK 0.125.0, `langchain-openai` 0.3.35, and `httpx` 0.28.1. -This is dated, point-in-time evidence, not a blanket compatibility guarantee; -see `references/known_deviations.md` for the observed scope and divergences. - -## Validate the skill - -Run deterministic repository checks and unit tests: - -```bash -python3 scripts/validate_skill.py -python3 -m unittest discover -s tests -v -``` - -Run the Agent Skills reference validator separately: - -```bash -uvx --from skills-ref agentskills validate "$PWD" -``` - -The reference validator checks format and naming conventions; it does not -verify that ECNU endpoints are currently available or that every documented -contract matches live behavior. - -## Maintenance principles - -- Official ECNU documentation is the authority for documented contracts. -- Upstream model cards and papers provide background, not ECNU API guarantees. -- Runtime observations must include a date and must remain labeled as - observations. -- Do not infer unsupported OpenAI or Anthropic fields. -- Keep examples minimal and secrets environment-based. -- Do not add local absolute paths or machine-specific deployment instructions. -- Run repository validation before opening a pull request. - -## Revalidate after ECNU platform updates - -An ECNU release, model rollout, endpoint change, quota change, or announced fix -is a reason to consider a new targeted validation; it is not evidence that an -active deviation has been resolved. Review the updated official contract, -recalculate the credit allowance, and run only the affected `--case` probes -serially with fresh sanitized evidence. Billable TTS or image probes require -new account-owner authorization and must never run automatically. - -Update an observation date or mark a deviation `resolved` only after the same -behavior has been exercised again with the current runner. Preserve the prior -entry when the new run is inconclusive, and record both the changed contract -and the new observed result when the platform update changes expectations. - -## Official documentation - -API details can change. Verify production-critical behavior against the current -ECNU developer documentation: - -- https://developer.ecnu.edu.cn/vitepress/llm/model.html -- https://developer.ecnu.edu.cn/vitepress/llm/thinking.html -- https://developer.ecnu.edu.cn/vitepress/llm/authorization.html -- https://developer.ecnu.edu.cn/vitepress/llm/limit.html -- https://developer.ecnu.edu.cn/vitepress/llm/error.html -- https://developer.ecnu.edu.cn/vitepress/llm/release.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/models.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/completions.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/responses.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/embedding.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/rerank.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/imagegenerate.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/audio.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/anthropic.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/structuredoutput.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/urlchat.html -- https://developer.ecnu.edu.cn/vitepress/llm/tos.html +| Start a normal integration | [SKILL.md](SKILL.md) | +| Find the relevant official endpoint contract | [Endpoint map](references/api_reference.md) | +| LangChain embeddings, thinking/tool history, Anthropic SDK | [Integration recipes](references/examples.md) | +| Model choice or current account facts | [Model/account pointers](references/models.md) | +| Diagnose a failure or select a live probe | [Targeted diagnosis](references/workflows.md) | +| Inspect dated evidence | [Known deviations](references/known_deviations.md) | +| Maintain this repository | [AGENTS.md](AGENTS.md) | +| Continue this simplification locally | [Implementation and handoff plan](docs/skill-refactor-plan.md) | + +The older [Agent-development notes](references/agent_development.md) remain to +preserve historical prompt-fixture references in the observation log. They are +not part of the default integration reading path or a current model benchmark. + +## Validation and evidence + +The existing runner and unit tests are retained. Maintainer commands are in +`AGENTS.md`; they are not steps for an Agent editing someone else's application. +Live checks require appropriate authorization and a cumulative credit budget. +A documentation edit is not a new live test: observation dates and statuses must +not be refreshed without reproducing the relevant behavior. + +Use current official pages for changing contracts, models, prices, and quotas. +Use local recipes to save integration work and dated observations to diagnose +specific discrepancies. Do not assume compatibility with every upstream feature. ## Disclaimer -This is an unofficial community skill. It is not endorsed by or affiliated with -East China Normal University. Never commit API keys, personal tokens, internal -allowlist details, private prompts, or unsanitized live-test output. +This community skill is not endorsed by or affiliated with East China Normal +University. Never commit credentials, private prompts, personal data, raw live +responses, generated media, or one-time access URLs. diff --git a/SKILL.md b/SKILL.md index 956fe92..146437e 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,255 +1,86 @@ --- name: ecnu-api description: > - Implement, review, test, or troubleshoot integrations with the ECNU - (East China Normal University) LLM Open Platform at chat.ecnu.edu.cn. - Use for OpenAI-compatible Chat Completions and Responses APIs, multimodal - input, embeddings, rerank, image generation, text-to-speech, structured - output, model discovery, Agent development, prompt design, - Anthropic-compatible clients, authentication, - credits, quotas, and API errors. Do not use for general ECNU information - or unrelated DeepSeek and Qwen questions. + Connect an application or SDK to the ECNU / ChatECNU LLM Open Platform + at chat.ecnu.edu.cn, or diagnose an ECNU API failure. Covers chat, + Responses, tools, vision, embeddings, rerank, images, TTS, and + Anthropic-compatible clients. Not for general ECNU information, + unrelated model questions, or generic Agent/prompt design. --- -# ECNU LLM Open Platform API - -Use this skill to turn ECNU API documentation into a safe, verifiable -integration. The current official ECNU developer documentation is the -authority for documented contracts. Keep documented facts, live observations, -upstream model background, application policy, and unverified claims separate. - -## Core rules - -1. Select the protocol root before constructing a request. -2. Use only fields documented by ECNU or explicitly verified against the - current service. -3. Do not assume that every OpenAI or Anthropic feature is implemented merely - because an endpoint is compatible with that protocol. -4. Keep API keys in environment variables. Never put a real key in source, - command history, examples, logs, screenshots, or committed test output. -5. Treat live observations as point-in-time evidence, not permanent contracts. -6. Avoid parallel calls. Run batches sequentially unless ECNU documents a safe - concurrency policy. - -## Workflow - -### 1. Classify the request - -Determine whether the user wants: - -- an explanation; -- implementation or code review; -- troubleshooting; -- a live capability check; -- a cost or quota calculation. - -Do not execute a real request when the user only asks for documentation or -sample code. - -### 2. Load only the relevant reference - -- Read [references/api_reference.md](references/api_reference.md) for endpoint - roots, request fields, limits, response shapes, and URL-parameter chat. -- Read [references/models.md](references/models.md) for model selection, - aliases, thinking modes, credits, quotas, deployment notes, and upstream - Qwen3.8 / DeepSeek / DSpark background with ECNU-specific boundaries. -- Read [references/agent_development.md](references/agent_development.md) for - model-specific Agent design, prompt templates, tools, context, and evaluation. -- Read [references/examples.md](references/examples.md) for minimal Python and - HTTP examples. -- Read [references/workflows.md](references/workflows.md) for implementation, - review, troubleshooting, retry, privacy, and live-verification procedures. -- Read [references/known_deviations.md](references/known_deviations.md) when - diagnosing behavior that conflicts with the official documentation. - -Do not load every reference for a narrow task. - -### 3. Select the protocol root - -| Protocol | Base or full URL | -|---|---| -| OpenAI-compatible | `https://chat.ecnu.edu.cn/open/api/v1` | -| Anthropic-compatible | `https://chat.ecnu.edu.cn/open/api/anthropic` | -| Embed iFrame | `https://chat.ecnu.edu.cn/open/api/embed/app` | - -The Anthropic messages URL is: - -```text -https://chat.ecnu.edu.cn/open/api/anthropic/v1/messages +# ECNU API integration + +Help the user finish the requested integration, not audit the whole platform. +Keep their working framework and chosen model unless the task requires a change. +Use the relevant official contract plus the ECNU-specific notes below. + +## Start with a working connection + +For a new, ordinary text integration, use `ecnu-plus` as a starting point. +This is an application default, not a claim that it is best for every task. +Read the key from `ECNU_API_KEY`; a missing key does not block writing code. +Install `openai` in the project's existing environment if it is needed. +This example makes one real request: do not run it for a code-only request. + +```python +import os +from openai import OpenAI + +client = OpenAI( + api_key=os.environ["ECNU_API_KEY"], + base_url="https://chat.ecnu.edu.cn/open/api/v1", + timeout=60.0, + max_retries=0, +) +response = client.chat.completions.create( + model="ecnu-plus", + messages=[{"role": "user", "content": "Reply with a short greeting."}], + max_tokens=128, +) +if not response.choices or response.choices[0].finish_reason != "stop": + raise RuntimeError("No complete text response; inspect the result before retrying") +text = response.choices[0].message.content +if not text: + raise RuntimeError("The response contained no text") +print(text) ``` -Never append the Anthropic path to the OpenAI-compatible `/v1` base. +For an Anthropic client, the base is +`https://chat.ecnu.edu.cn/open/api/anthropic`, not the OpenAI `/v1` base. +Its full messages URL ends in `/open/api/anthropic/v1/messages`. -### 4. Select a model +## Read only what this task needs -| Task | Preferred model | +| Task | Next resource | |---|---| -| General text, tools, lower token price | `ecnu-plus` | -| Complex text or code | `ecnu-max` | -| Image understanding | `ecnu-plus`; `ecnu-max` for complex visual reasoning | -| Structured JSON | `ecnu-plus` or `ecnu-max` | -| Embeddings | `ecnu-embedding-small` | -| Rerank | `ecnu-rerank` | -| Image generation | `ecnu-image` | -| Text-to-speech | `ecnu-tts` | - -Use `ecnu-max` and `ecnu-plus` for new dialog integrations. Treat historical -names as compatibility aliases. - -### 5. Validate the request contract - -#### Embeddings - -- `input` must be one string or an array of strings. -- Do not send OpenAI token-ID arrays. -- ECNU documents a 1024-float output vector. -- The direct ECNU request documents `model` and `input`; do not add an - unsupported dimension-selection request field. -- With LangChain `OpenAIEmbeddings`, set - `check_embedding_ctx_length=False` so raw strings are sent. Verify the - returned vector length after the request. - -#### Rerank - -- `documents` must be a string array. -- `query` must be a string. -- Each document is limited to 8192 characters. -- `top_n` defaults to 5. ECNU publishes no maximum document count, maximum - `top_n`, or query-length limit. - -#### Vision - -- Use Chat Completions with structured `text` and `image_url` content parts. -- Both `ecnu-plus` and `ecnu-max` now document image understanding. Verify each - protocol separately; the older `ecnu-max` failure is historical evidence. -- A public URL or base64 data URL may be used. -- Do not convert a ChatECNU web-UI upload limit into an API limit. - -#### Image and audio - -- Image prompts are limited to 1024 characters; prompts over 500 characters - may be compressed. -- Image URLs expire after 24 hours. -- TTS input is limited to 4096 characters. -- TTS speed is 0.25 through 4.0. - -#### Structured output - -- Both primary dialog models support `json_schema` and `json_object`. -- Parse raw JSON without removing Markdown fences; check completion and - validate the supplied schema. Valid structure does not ensure correct facts. - -### 6. Protect secrets, data, and credits - -Before a real request: - -- recheck the current official quota and pricing page, then calculate a - conservative planned cost from those documented prices; -- use 50 credits as the default ceiling and do not run a larger plan without - separate user authorization; -- use only `ECNU_API_KEY` from the environment; never accept a key through a - command-line argument; -- remove secrets and unnecessary personal or confidential data; -- verify that existing conversation authorization covers the account, supplied - content, ECNU destination, and planned purpose; ask only if that coverage is - missing or materially changes, and preserve any explicit per-action approval; -- execute requests serially; and -- never retry a POST after an ambiguous timeout or connection failure. - -Reuse authorization within the same approved batch. Track cumulative planned -and consumed credits against the batch ceiling; do not reset the allowance -for each request. Missing data authorization blocks only the affected request, -not independent offline preparation or validation. - -If the full plan exceeds 50 credits, preserve the core dialog, embedding, -rerank, compatibility, and error checks; prefer one TTS PCM check; run at most -one documented image-generation case; and skip expanded voices and -undocumented model probes. - -If a key has already been pasted into a chat or public location, recommend -revoking or rotating it after testing. - -### 7. Execute and verify - -Use the smallest profile that answers the question. Sanitized reports belong -under the ignored `.live-artifacts/` directory: - -```bash -python3 scripts/smoke_test.py --profile auth --max-credits 0 --output .live-artifacts/auth.json -python3 scripts/smoke_test.py --profile core --max-credits 50 --output .live-artifacts/core.json -python3 scripts/smoke_test.py --profile compatibility --max-credits 50 --output .live-artifacts/compatibility.json -python3 scripts/smoke_test.py --profile billable --max-credits 50 --output .live-artifacts/billable.json -python3 scripts/smoke_test.py --profile all --max-credits 50 --output .live-artifacts/all.json -``` - -The default profile is `auth`. The runner reads `ECNU_API_KEY`, executes -serially with POST retries disabled, reserves estimated credits before each -request, skips cases that would exceed the ceiling, and emits response -structure rather than generated content. A credit estimate is not proof of the -service's actual debit. - -### 8. Report provenance - -Label important conclusions as one of: - -- **`documented`** — supported by the current official ECNU documentation. -- **`upstream-background`** — supported by original model cards or papers; - not proof of ECNU endpoint capabilities, defaults, or performance. -- **`observed`** — reproduced against the live service at a stated date. -- **`application-policy`** — a local safety, cost, or reliability constraint; - not an ECNU platform guarantee. -- **`unverified`** — inferred, historical, or not reproducible in the current - environment. - -Do not silently promote an observed deviation into a documented guarantee. - -### 9. Finish repository work - -When repository files changed, finish with offline, format, and secret checks: - -```bash -python3 scripts/validate_skill.py -python3 -m unittest discover -s tests -v -python3 -m compileall scripts tests -uvx --from skills-ref agentskills validate "$PWD" -git grep -nE 'sk-[A-Za-z0-9_-]{16,}' -git grep -nE 'Authorization:[[:space:]]*Bearer[[:space:]]+[^<"$]' -git diff --check -``` - -Review every secret-scan match; no tracked literal credential may remain. -Variable-based test fixtures may match the coarse Bearer expression. If `uvx` -is not available, report that validator as not run rather than treating it as -live API evidence. - -## High-value gotchas - -- `GET /models` is runtime discovery, not a reliable authentication test. -- A model appearing in `/models` does not prove that a capability is usable. -- Use `ecnu-max[1m]` only when an Anthropic tool requires the suffix to - advertise long context. Consider plain `ecnu-max` only when the same - credential already succeeds with that model, the suffixed request returns - the observed suffix-specific `401` metadata error, and the caller accepts - the shorter advertised context. -- TTS errors may not match the documented JSON shape; preserve the HTTP status, - content type, and a bounded redacted body sample. -- Do not assume the documented PCM metadata headers are present; check them at - runtime and configure the format explicitly when they are absent. -- `422` means request validation failed; inspect `detail`. -- `429` may represent quota exhaustion, rate control, or short-term service - protection. Stop parallel retries and inspect credits first. - -## Official documentation - -- Models: https://developer.ecnu.edu.cn/vitepress/llm/model.html -- Thinking: https://developer.ecnu.edu.cn/vitepress/llm/thinking.html -- API index: https://developer.ecnu.edu.cn/vitepress/llm/api/models.html -- Responses: https://developer.ecnu.edu.cn/vitepress/llm/api/responses.html -- Structured output: https://developer.ecnu.edu.cn/vitepress/llm/api/structuredoutput.html -- URL chat: https://developer.ecnu.edu.cn/vitepress/llm/api/urlchat.html -- Quotas: https://developer.ecnu.edu.cn/vitepress/llm/limit.html -- Errors: https://developer.ecnu.edu.cn/vitepress/llm/error.html -- Release notes: https://developer.ecnu.edu.cn/vitepress/llm/release.html -- Data security: https://developer.ecnu.edu.cn/vitepress/llm/security.html -- Developer agreement: https://developer.ecnu.edu.cn/vitepress/llm/tos.html -- Service status: https://chat.ecnu.edu.cn/status +| Chat, streaming, vision, Responses, JSON, rerank, images, TTS, or browser integration | [Official endpoint map](references/api_reference.md): open only the matching page | +| LangChain embeddings or Anthropic SDK setup | [Integration recipes](references/examples.md): read the matching section | +| Thinking and tool continuation | [Tool-history recipe](references/examples.md#thinking-and-tool-history) plus the linked ECNU contract | +| Model choice, prices, quotas, or deployment questions | [Model and account pointers](references/models.md) | +| An error, unexpected result, or requested live check | [Targeted diagnosis](references/workflows.md); consult only the matching dated deviation | + +A basic code edit does not require reading all references or running a smoke +profile. API compatibility is not proof that every upstream field is supported. +Current official pages define documented contracts; local observations are dated +exceptions, not permanent guarantees. If a page is unreachable, use relevant +local material to continue offline work and state what could not be rechecked. +Do not present an old price, quota, or capability as freshly verified. + +## Execution boundary + +Only make live requests when needed and covered by the user's authorization +for the account, data, destination, purpose, and budget. Reuse authorization +within that scope; ask only about a missing or materially changed part. +Never request a key in chat or put credentials, private prompts, or reasoning +in logs. A missing execution permission blocks that request, not offline work. + +For live probes, check current prices, use synthetic input, run serially, and +select the smallest relevant case. The runner's default ceiling is 50 credits, +not permission to spend them; obey any lower approved limit and obtain separate +authorization before exceeding 50. Do not reset the budget per request. +Do not automatically repeat a possibly accepted POST after a timeout or dropped +connection. See the diagnosis reference only when execution is actually needed. + +Finish with the requested code or answer and what was actually checked. +Do not impose a provenance-report template on routine work. Repository-maintainer +checks belong in `AGENTS.md`, not in a consuming application's workflow. diff --git a/docs/skill-refactor-plan.md b/docs/skill-refactor-plan.md new file mode 100644 index 0000000..9d2a69c --- /dev/null +++ b/docs/skill-refactor-plan.md @@ -0,0 +1,88 @@ +# ECNU Skill 实用化改版与本地接续计划 + +## 目标 + +让用户少交代 ECNU 背景,让 Agent 少找资料、少猜兼容性、少重复写接入逻辑。 +不是追求最短文件、完整复制官网,也不是搭建跨模型评测平台。 +默认路径应当支持普通任务直接开始;只有任务需要时才进入详细排障或真实验证。 + +## 本 PR 的范围 + +| 文件 | 改动 | 验收边界 | +|---|---|---| +| `SKILL.md` | 九步通用流程改为最小接入、任务导航、执行边界 | 写代码不需要密钥,不强制全量 smoke 或固定报告 | +| `references/api_reference.md` | 参数表副本改为官方接口导航 | 原有能力仍有官方入口,不让用户自己找链接 | +| `references/models.md` | 保留默认选择与账号来源,移除价格/配额和上游架构副本 | 不把旧数值或上游能力当作当前 ECNU 契约 | +| `references/examples.md` | 聚焦 Embedding、工具历史、Anthropic 三个接入配方 | 不复制整套 SDK;工具代码片段明确前置条件 | +| `references/workflows.md` | 按症状找证据,按需选择最小验证 | 保留授权、预算、脱敏、串行和不盲重试边界 | +| `README.md`、`AGENTS.md` | 区分使用者与维护者,提供接续入口 | 业务项目不运行 Skill 仓库的维护命令 | + +保留 `scripts/`、`tests/` 和 CI,不重写已有测试工具。 +保留 `known_deviations.md` 的全部原始记录、日期与状态。 +保留 `agent_development.md`,因为旧实测记录引用其中的具体提示词; +它退出默认接入路径,但不在此次改版中删除历史证据的来源。 + +本 PR 不运行真实 ECNU 请求,不新增 SDK、不新增评测平台,不自动合并。 +代码示例的改写不代表这些新文本已做实网复测。 + +## 本地 Codex 接续 + +在本 PR 分支继续,先检查工作区,不覆盖本地未提交改动。 +先读 `AGENTS.md`、本计划和 diff,不需要重新研究整个 Agent Skills 体系。 + +### 1. 完成常规离线检查 + +运行 `AGENTS.md` 中的验证、单元测试、编译、格式检查。 +参考格式验证器不可用时如实记录,不为它阻塞独立工作。 +检查 Markdown 相对链接、章节锚点和示例代码;不执行示例里的网络请求。 +尤其确认依赖版本下的 Embedding 参数和 SDK 消息序列化行为。 +修复真实问题,不新增长篇原则,也不为迎合旧目录结构削弱安全检查。 + +### 2. 用三个日常请求走查,不做模型矩阵 + +在平时使用的 Agent/模型环境中,开启独立任务会话,使用本分支材料。 +确认加载的不是旧全局安装版;不要手工覆盖已安装的 skill 目录。 +走查时不读取、复制或提交真实凭据,默认只写代码或使用合成响应。 + +| 请求 | 看什么 | +|---|---| +| 给现有 Python 项目接 ECNU,只生成代码 | 是否直接开始,是否找对相关文档,有无无关阅读和多余流程 | +| 把现有 LangChain Embedding 改为 ECNU | 实际请求是否保持原始字符串,而不只是答案中提到配置 | +| 给出一个失败样例,例如 `/models` 返回空列表 | 是否给出针对性诊断,而非全量测试、武断鉴权结论或反复确认 | + +不要求每个任务重复多次、不打综合分。简短记录“还需要我补充什么”以及 +“Skill 让 Agent 多做了什么”。若使用 mock,结论只能覆盖 mock 条件。 +一次真实使用没有暴露问题,不等于证明所有模型或所有任务都已覆盖。 + +### 3. 只围绕实际阻力补充 + +| 发现 | 优先处理 | +|---|---| +| Agent 不知道去哪查 | 修正对应文档入口 | +| 反复猜错 ECNU 特有配置 | 在对应配方补最小说明 | +| 重复实现同一段稳定代码 | 优先改现有样例;确认反复使用后再考虑脚本 | +| 因 Skill 读取无关材料或过度检查 | 缩小触发条件,删除或下沉要求 | +| 仅一次通用推理失误 | 先不加永久规则,避免为每次失误堆提示词 | + +至少确认有价值的配方仍容易找到,不能为了缩短行数删掉必要约束。 +没有实际阻力就停止,不为“补充”而补充。 + +## 只有确有必要时才做真实验证 + +真实请求需要账号、数据、目的和预算范围内的授权。 +在同一范围内复用授权;超范围、超预算或明确要求逐次审批时再确认。 +按当前价格选择一个相关 case,不跑 `all`,不顺带生成图片或语音。 +保留现有脚本的默认预算上限和更低的用户批准额度,跨次运行累计计算。 +脱敏结果留在忽略目录;只有实际复现后才修改对应观察记录。 + +## 合并前验收 + +- 普通代码请求能推进,不因缺密钥或不能实网验证而停止独立工作。 +- 官方导航覆盖原有主要能力;价格和模型表不再多处手工同步。 +- 接入配方、历史偏差、维护流程各有入口,不默认全部加载。 +- 当前文档、历史观察、本地默认策略没有混成同一种保证。 +- 原有离线测试和安全边界保留;实际未执行的检查明确标注。 +- 用本地实际任务确认没有明显新增阻力;这不是跨模型效果承诺。 + +合并由维护者决定。更换模型后遇到具体问题再调整,不预先维护所有模型矩阵。 +未来若反复遇到同类障碍,再决定是否继续拆分历史资料或新增可执行工具。 diff --git a/references/api_reference.md b/references/api_reference.md index 955dbe7..acf2bb4 100644 --- a/references/api_reference.md +++ b/references/api_reference.md @@ -1,425 +1,44 @@ -# ECNU API Reference +# Official endpoint map -This file contains documented request contracts. Point-in-time service -differences belong in [known_deviations.md](known_deviations.md), not here. +Use this as a router, not a second copy of ECNU's parameter tables. Open the +page for the requested capability; there is no prerequisite to read every page. +The small local recipes cover integration details that otherwise get rediscovered. -## Protocol roots and authentication +## Protocol roots -### OpenAI-compatible APIs - -```text -https://chat.ecnu.edu.cn/open/api/v1 -``` - -Use this base for Chat Completions, Responses, embeddings, rerank, images, TTS, -and models. - -### Anthropic-compatible API - -```text -Base: https://chat.ecnu.edu.cn/open/api/anthropic -Messages: https://chat.ecnu.edu.cn/open/api/anthropic/v1/messages -``` - -### Embed iFrame - -```text -https://chat.ecnu.edu.cn/open/api/embed/app -``` - -### Authentication - -```http -Authorization: Bearer -Content-Type: application/json -``` - -Use environment variables. Tokens are personal and the developer agreement -states that their default validity is 90 days. - -## Endpoint map - -| Capability | Method and path | Model | -|---|---|---| -| Chat Completions | `POST /chat/completions` | `ecnu-max`, `ecnu-plus` | -| Responses | `POST /responses` | `ecnu-max`, `ecnu-plus` | -| Vision | `POST /chat/completions` | `ecnu-plus` | -| Embeddings | `POST /embeddings` | `ecnu-embedding-small` | -| Rerank | `POST /rerank` | `ecnu-rerank` | -| Image generation | `POST /images/generations` | `ecnu-image` | -| Text-to-speech | `POST /audio/speech` | `ecnu-tts` | -| Model list | `GET /models` | N/A | -| Structured output | `POST /chat/completions` | `ecnu-plus`, `ecnu-max` | -| Anthropic messages | full URL above | dialog models and mappings | -| Embed iFrame | full URL above | N/A | - -URL-parameter chat is a browser integration, described separately below, not -an endpoint under either API root. - -## Chat Completions - -```http -POST https://chat.ecnu.edu.cn/open/api/v1/chat/completions -``` - -Documented request fields include: - -| Field | Type | Notes | -|---|---|---| -| `model` | string | Prefer `ecnu-max` or `ecnu-plus` | -| `messages` | array | Ordered messages | -| `messages[].role` | string | `system`, `user`, or `assistant` | -| `messages[].content` | string or array | Array form is used for vision | -| `stream` | boolean | Streams SSE when true | -| `temperature` | number | 0 through 1 | -| `top_p` | number | 0 through 1 | -| `tools` | array | OpenAI-compatible function definitions | -| `thinking` | object | `{"type":"enabled"}` or `{"type":"disabled"}` | -| `reasoning_effort` | string | `low`, `high`, or `max`; `ecnu-max` only | -| `response_format` | object | Structured output | -| `max_tokens` | integer | Use enough room for complete output | - -A live-verified tool-result continuation preserves the assistant tool call, -then adds a message with `role: "tool"`, the matching `tool_call_id`, and the -tool result in `content`. - -Pass ECNU-specific fields through `extra_body` when using the OpenAI Python -SDK. - -`reasoning_effort` only applies when thinking is enabled and only to -`ecnu-max`. `ecnu-plus` ignores it. Sampling controls may not take effect or -may be restricted in thinking mode. - -If a tool was called during a thinking-mode conversation, retain the returned -assistant `reasoning_content` in subsequent history, including later user -turns. Do not discard it after the first tool result. Keep it out of logs and -user-facing output; see [Agent development](agent_development.md). -Keep the complete original message. The -[live reasoning-field observation](known_deviations.md#max-thinking-response-fields) -records a deployment difference without changing this documented contract. - -A non-streaming response follows the OpenAI completion-list shape with -`choices[].message`, `finish_reason`, and `usage`. For streaming, parse SSE -`data:` lines and stop at `[DONE]`. - -Do not require a response `model` value to equal the requested model name. The -official examples either omit that field or show a backend label different from -the requested name. Treat it as response metadata, not a stable alias echo. - -Native `search_mode` web search was removed. Implement search through tool -calling or an external search service. - -## Responses API - -```http -POST https://chat.ecnu.edu.cn/open/api/v1/responses -``` - -Both primary dialog models support the Responses wire format. The ECNU page -does not publish a complete ECNU-specific field and event matrix. Start with -text input and verify advanced OpenAI Responses tools or event types before -depending on them. - -For `ecnu-max`, `reasoning.effort` controls thinking intensity. The compatibility -layer maps `minimal`/`low` to `low`, `medium`/`high`/`xhigh` to `high`, and -`max` to `max`; `none` disables thinking. `ecnu-plus` ignores this field. - -## Vision - -Both `ecnu-plus` and `ecnu-max` support Chat Completions image input according -to the current model and endpoint pages. This lower-cost example uses -`ecnu-plus`: - -```json -{ - "model": "ecnu-plus", - "messages": [ - { - "role": "user", - "content": [ - {"type": "text", "text": "Describe this image."}, - { - "type": "image_url", - "image_url": {"url": "data:image/jpeg;base64,"} - } - ] - } - ] -} -``` - -`image_url.url` may be a public URL or a base64 data URL. The API page does not -publish a maximum image count, byte size, pixel size, or MIME-type matrix. -Do not reuse a web-UI upload limit as an API contract. - -The direct `ecnu-max` failure recorded on 2026-08-23 predates its V4.1 upgrade. -Do not apply that historical limitation to the current documented contract. -Responses and Anthropic image handling still need protocol-specific validation. - -## Embeddings - -```http -POST https://chat.ecnu.edu.cn/open/api/v1/embeddings -``` - -| Field | Type | Required | Contract | -|---|---|---|---| -| `model` | string | Yes | `ecnu-embedding-small` | -| `input` | string or string[] | Yes | Raw text only | - -Unsupported forms include integer token IDs and arrays of integer token arrays. -ECNU uses a non-OpenAI tokenizer. - -The published input limit is 8192 characters, but the page does not specify -whether an array is checked per item, by combined length, or both. It publishes -no maximum batch item count. - -The output contains 1024 floating-point values per embedding. The direct -request contract does not document a dimension-selection field. With LangChain, -disable automatic token-length conversion and validate output length after the -response. - -## Rerank - -```http -POST https://chat.ecnu.edu.cn/open/api/v1/rerank -``` - -The request is Cohere-compatible rather than part of the OpenAI SDK surface. - -| Field | Type | Required | Contract | -|---|---|---|---| -| `model` | string | Yes | `ecnu-rerank` | -| `documents` | string[] | Yes | Each document at most 8192 characters | -| `query` | string | Yes | Search query | -| `return_documents` | boolean | No | Include document text | -| `top_n` | integer | No | Defaults to 5 | - -No maximum document count, maximum `top_n`, or query-length limit is published. - -## Image generation - -```http -POST https://chat.ecnu.edu.cn/open/api/v1/images/generations -``` - -| Field | Type | Required | Contract | -|---|---|---|---| -| `model` | string | Yes | `ecnu-image` | -| `prompt` | string | Yes | At most 1024 characters | -| `size` | string | No | Defaults to `512x512` | -| `response_format` | string | No | `url` or `b64_json` | - -Documented sizes: - -```text -512x512 -768x768 -720x1280 -1280x720 -1024x1024 -``` - -Prompts over 500 characters may be compressed. URL results are retained for 24 -hours, so transfer them promptly. Treat retries after ambiguous failures as -potential duplicate charges. - -## Text-to-speech - -```http -POST https://chat.ecnu.edu.cn/open/api/v1/audio/speech -``` - -| Field | Type | Required | Contract | -|---|---|---|---| -| `model` | string | Yes | `ecnu-tts` | -| `input` | string | Yes | At most 4096 characters | -| `voice` | string | No | Defaults to `xiayu` | -| `response_format` | string | No | `mp3`, `opus`, `aac`, `flac`, `wav`, `pcm` | -| `speed` | number | No | 0.25 through 4.0 | - -The 16 documented voice IDs are: - -| Category | Voice IDs | -|---|---| -| Campus | `xiayu`, `liwa` | -| Male | `male_warm`, `male_steady`, `male_news`, `male_philosophy`, `yunze` | -| Female | `female_sweet`, `female_literary`, `female_news` | -| Dialect | `sichuan`, `tianjin`, `shaanxi` | -| Multilingual and roles | `japanese`, `lindaiyu`, `labixiaoxin` | - -The success body is binary audio with a format-specific `Content-Type` and a -`Content-Disposition` header containing a suggested filename. Do not parse it -as JSON. For `pcm`, the documented response also includes `Content-Rate` -(sampling rate), `Content-Channels` (fixed at 1), and `Content-Bits` (fixed at -16). - -Invalid parameters are documented to return `400` JSON with this shape: - -```json -{ - "error": "", - "request_id": "", - "details": { - "available_voices": ["xiayu", "liwa"] - } -} -``` - -The documented `details` object supplies applicable supplemental information; -the invalid-voice example uses `available_voices`. Other documented messages -cover missing input, out-of-range speed, and unsupported response formats. - -"Batch TTS" examples are sequential client loops, not one batch request. - -## Model list - -```http -GET https://chat.ecnu.edu.cn/open/api/v1/models -``` - -The official request example uses bearer authentication and has no request -parameters. The documented response is an OpenAI-style list with a top-level -`object: "list"` and model entries in `data`; each entry has `id`, `object` -(fixed to `model`), `created`, and `owned_by`. - -Use this endpoint for runtime visibility, then consult the model documentation -for capabilities, aliases, and prices. Do not treat visibility alone as a -capability guarantee. Dated runtime differences, including authentication -behavior, belong in [known_deviations.md](known_deviations.md) and do not change -the documented contract here. - -## Structured output - -Both `ecnu-plus` and `ecnu-max` support constrained decoding through -SGLang / XGrammar. `response_format.type` accepts `json_schema` (recommended) -or `json_object`. For `json_schema`, the nested `name` and `schema` are -required; the schema may describe an object or an array. - -```json -{ - "response_format": { - "type": "json_schema", - "json_schema": { - "name": "result", - "schema": { - "type": "object", - "properties": { - "name": {"type": "string"} - }, - "required": ["name"] - } - } - } -} -``` - -For JSON-object output without a supplied schema, use: - -```json -{"response_format":{"type":"json_object"}} -``` - -The current documentation states that constrained output remains raw JSON even -when a prompt asks for Markdown fences. Parse the original content directly; -do not strip fences to hide a contract mismatch. Check `finish_reason`, parse -JSON, and validate the schema when supplied. `json_object` alone does not -guarantee specific fields. XGrammar constrains structure, not factual or -semantic correctness. Allocate enough `max_tokens` to complete the output. - -## Anthropic-compatible messages - -Set: - -```text -ANTHROPIC_BASE_URL=https://chat.ecnu.edu.cn/open/api/anthropic -ECNU_API_KEY= -``` - -Pass `ECNU_API_KEY` explicitly to the Anthropic SDK as its `api_key`. Only if a -generic Anthropic client cannot accept that variable name, map the same runtime -value to the client-specific token variable without logging or persisting it. - -Documented mappings: - -| Requested name | Effective model | +| Client / integration | Base or full URL | |---|---| -| `ecnu-max` | `ecnu-max` | -| `ecnu-plus` | `ecnu-plus` | -| `opus` family | `ecnu-max` | -| `sonnet` or `haiku` family | `ecnu-plus` | -| other unrecognized names | `ecnu-plus` | - -The documentation describes `ecnu-max[1m]` for Anthropic tools that inspect the -model name to advertise a 1M-character context. Treat the suffix as -compatibility metadata, not a model name for OpenAI-compatible endpoints. - -These mappings describe internal compatibility routing. The Anthropic page does -not document whether a response `model` value echoes the requested alias or -names the effective ECNU model, so clients must not depend on either behavior. - -`output_config.effort` controls thinking intensity for `ecnu-max`; `none` -disables thinking. `ecnu-plus` ignores this field. - -## Embed iFrame +| OpenAI-compatible | `https://chat.ecnu.edu.cn/open/api/v1` | +| Anthropic-compatible base | `https://chat.ecnu.edu.cn/open/api/anthropic` | +| Anthropic messages | `https://chat.ecnu.edu.cn/open/api/anthropic/v1/messages` | +| Embed ticket endpoint | `https://chat.ecnu.edu.cn/open/api/embed/app` | -```http -POST https://chat.ecnu.edu.cn/open/api/embed/app -``` +Do not concatenate the Anthropic path onto the OpenAI base. Keep credentials +in environment variables; ticket URLs are also credentials. -The documented request uses `client_id`, `client_secret`, `userid`, -`username`, and `appid`. Returned tickets and URLs are credentials. Do not log -or persist them. Tickets are one-time use and expire. +## Pick the contract for the task -## URL-parameter chat - -```text -https://chat.ecnu.edu.cn/html/#/chat?submit={ENCODED_QUERY} -``` - -`submit` is a required UTF-8 question string encoded with JavaScript -`encodeURIComponent`. Opening the link decodes and fills the prompt, creates -a new ChatECNU conversation, and automatically sends the question once. When -logged out, the user goes through school SSO and then returns with the question -preserved for automatic submission. - -This is browser navigation, not an API POST or an authenticated iframe ticket. -Do not put API keys or confidential prompts in a shareable URL. Constructing -the URL is inert; opening it sends the question, so do not auto-open examples -as a documentation check. - -## Errors and undocumented limits - -| Status | Typical meaning | -|---|---| -| `400` | Invalid TTS parameters; `/audio/speech` documents an endpoint-specific JSON error | -| `401` | Missing or invalid credentials | -| `403` | Application or client IP is not authorized | -| `422` | Request body validation failed | -| `429` | Quota, rate control, or short-term service protection | -| `5xx` | Server, proxy, or undocumented compatibility failure | - -`detail` may be a string or an array of validation objects. Preserve the HTTP -status, content type, and a bounded redacted body sample. Do not assume every -error is JSON. - -When ECNU publishes no limit, say "not documented." Do not substitute an OpenAI -default, model-card value, UI limit, or one-time observation. - -## Official sources - -- https://developer.ecnu.edu.cn/vitepress/llm/model.html -- https://developer.ecnu.edu.cn/vitepress/llm/thinking.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/models.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/completions.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/responses.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/embedding.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/rerank.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/imagegenerate.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/audio.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/anthropic.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/structuredoutput.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/embediframe.html -- https://developer.ecnu.edu.cn/vitepress/llm/api/urlchat.html -- https://developer.ecnu.edu.cn/vitepress/llm/error.html -- https://developer.ecnu.edu.cn/vitepress/llm/tos.html +| Task | Official documentation | Local addition when needed | +|---|---|---| +| Chat, streaming, tools, image understanding | [Chat Completions](https://developer.ecnu.edu.cn/vitepress/llm/api/completions.html) | [Thinking/tool history](examples.md#thinking-and-tool-history) | +| Responses-compatible client | [Responses](https://developer.ecnu.edu.cn/vitepress/llm/api/responses.html) | Verify the specific advanced tool/event support; compatibility alone is insufficient | +| JSON Schema or JSON object output | [Structured output](https://developer.ecnu.edu.cn/vitepress/llm/api/structuredoutput.html) | Check completion, parse raw JSON, and validate the supplied schema; do not hide a mismatch by stripping fences | +| Embeddings | [Text vectors](https://developer.ecnu.edu.cn/vitepress/llm/api/embedding.html) | [Raw-string LangChain recipe](examples.md#langchain-embeddings) | +| Rerank | [Rerank](https://developer.ecnu.edu.cn/vitepress/llm/api/rerank.html) | Use the endpoint's contract, not an assumed OpenAI SDK method | +| Image generation | [Images](https://developer.ecnu.edu.cn/vitepress/llm/api/imagegenerate.html) | Observe the current URL lifetime and avoid duplicate paid generations | +| Text-to-speech | [Audio](https://developer.ecnu.edu.cn/vitepress/llm/api/audio.html) | [Non-JSON errors and PCM headers](workflows.md#start-from-the-symptom) | +| Model discovery | [Models endpoint](https://developer.ecnu.edu.cn/vitepress/llm/api/models.html) | A visible ID does not prove usable capability or valid authentication | +| Anthropic-compatible client | [Anthropic API](https://developer.ecnu.edu.cn/vitepress/llm/api/anthropic.html) | [SDK setup](examples.md#anthropic-sdk); investigate suffix errors only when they occur | +| Embed an iframe | [Embed integration](https://developer.ecnu.edu.cn/vitepress/llm/api/embediframe.html) | Do not log or reuse one-time tickets | +| Browser link that submits a question | [URL chat](https://developer.ecnu.edu.cn/vitepress/llm/api/urlchat.html) | Opening a submit link sends data; do not auto-open it as a documentation check | + +## Account and changing values + +Use [model/account pointers](models.md) for models, thinking, current pricing, +quotas, credentials, data handling, and release notes. Do not maintain duplicate +copies of those changing tables here. + +When documentation and behavior disagree, use the matching +[dated deviation](known_deviations.md). The current official page is the +contract; a dated observation describes one tested environment. Neither a +model card nor an accepted over-limit request establishes an ECNU API limit. diff --git a/references/examples.md b/references/examples.md index c1dcff6..b9fe0c2 100644 --- a/references/examples.md +++ b/references/examples.md @@ -1,627 +1,116 @@ -# ECNU API Examples +# Integration recipes -These examples use environment variables, explicit request shapes, and -sequential calls. They avoid undocumented parameters. +Read only the section matching the current task. These are small integration +patterns, not a replacement SDK or a complete application. For ordinary chat, +use the example in [SKILL.md](../SKILL.md); for other endpoints, go straight to +the [official page](api_reference.md). -The OpenAI SDK chat, Responses, and embedding paths, the Anthropic SDK -`ecnu-plus` path, and the LangChain embedding path below were live-verified on -**2026-08-23** with Python 3.9.6, OpenAI 2.48.0, Anthropic 0.125.0, and -langchain-openai 0.3.35. This is dated compatibility evidence, not a guarantee -for other versions. +The executable examples below make real requests when run. Use the project's +existing environment and dependencies; do not install or run them for a +code-only request. Live execution follows the authorization and budget boundary +in the skill. Rewritten snippets are not new live-verification evidence; +[dated observations](known_deviations.md) retain their original scope and dates. -## Setup +## LangChain embeddings -```bash -python3 -m pip install openai requests -export ECNU_API_KEY="your-api-key" -``` - -```python -import os -from openai import OpenAI - -api_key = os.environ["ECNU_API_KEY"] - -client = OpenAI( - api_key=api_key, - base_url="https://chat.ecnu.edu.cn/open/api/v1", - timeout=60.0, - max_retries=0, -) -``` - -Disabling SDK retries prevents an ambiguous POST failure from being submitted -again. Treat such a transport failure as inconclusive. - -## Chat Completions - -```python -completion = client.chat.completions.create( - model="ecnu-plus", - messages=[ - {"role": "system", "content": "Answer accurately and concisely."}, - {"role": "user", "content": "用一句话介绍华东师范大学。"}, - ], -) - -if not completion.choices: - raise RuntimeError("chat response contained no choices") -content = completion.choices[0].message.content or "" -print(content) -``` - -## Responses API - -```python -response = client.responses.create( - model="ecnu-max", - input="用一句话介绍华东师范大学。", -) - -text = getattr(response, "output_text", None) or "" -if not text: - raise RuntimeError("response contained no text output") -print(text) -``` - -Start with text input. Verify advanced Responses tools and streaming events -before depending on them. - -## Thinking mode - -Pass ECNU extensions through `extra_body`: - -```python -completion = client.chat.completions.create( - model="ecnu-max", - messages=[{"role": "user", "content": "Analyze this problem."}], - extra_body={ - "thinking": {"type": "enabled"}, - "reasoning_effort": "high", - }, -) - -if not completion.choices: - raise RuntimeError("thinking response contained no choices") -message = completion.choices[0].message -answer = message.content or "" -print(answer) -``` - -Do not print or persist hidden reasoning. For assistant messages that call -tools in thinking mode, retain `reasoning_content` in memory throughout the -continuing conversation, including later user turns. Discard it when the -conversation ends, not just after the first tool result. See -[Agent development](agent_development.md) for the complete tool exchange. -Preserve the complete returned message and consult the -[reasoning-field observation](known_deviations.md#max-thinking-response-fields) -when `reasoning_content` is absent; do not invent the missing field. - -## Streaming - -```python -stream = client.chat.completions.create( - model="ecnu-plus", - messages=[{"role": "user", "content": "Tell me a short story."}], - stream=True, -) +The [ECNU embedding contract](https://developer.ecnu.edu.cn/vitepress/llm/api/embedding.html) +accepts strings, not OpenAI token-ID arrays. Disable LangChain's token conversion. +Validate the returned length instead of sending a dimension-selection field: +the direct endpoint contract documents `model` and `input`, and a 1024-value +output, not selectable dimensions. Reject an empty list before making a call. -for chunk in stream: - choices = getattr(chunk, "choices", None) or [] - if not choices: # Usage-only and keepalive chunks may have no choices. - continue - text = getattr(choices[0].delta, "content", None) - if text: - print(text, end="", flush=True) -``` - -## Tool calling - -```python -tools = [ - { - "type": "function", - "function": { - "name": "get_current_weather", - "description": "Get current weather for a city.", - "parameters": { - "type": "object", - "properties": { - "location": {"type": "string"}, - }, - "required": ["location"], - }, - }, - } -] - -completion = client.chat.completions.create( - model="ecnu-plus", - messages=[{"role": "user", "content": "What's the weather in Shanghai?"}], - tools=tools, -) - -if not completion.choices: - raise RuntimeError("tool response contained no choices") -for call in getattr(completion.choices[0].message, "tool_calls", None) or []: - print(call.id, call.function.name, call.function.arguments) -``` - -The caller must execute the function and submit the tool result in a subsequent -turn. - -## Vision - -Both primary models document image input through Chat Completions. This -example uses `ecnu-plus`; `ecnu-max` is also a documented option. - -```python -completion = client.chat.completions.create( - model="ecnu-plus", - messages=[ - { - "role": "user", - "content": [ - {"type": "text", "text": "Describe this image."}, - { - "type": "image_url", - "image_url": {"url": "https://example.com/image.jpg"}, - }, - ], - } - ], -) - -if not completion.choices: - raise RuntimeError("vision response contained no choices") -print(completion.choices[0].message.content or "") -``` - -For a local image, base64-encode it into a data URL. Do not assume undocumented -image-count, byte-size, or pixel limits. - -## Embeddings - -One text: - -```python -response = client.embeddings.create( - model="ecnu-embedding-small", - input="华东师范大学", -) - -if not response.data: - raise RuntimeError("embedding response contained no vectors") -vector = response.data[0].embedding -assert len(vector) == 1024 -``` - -Several texts in one request: - -```python -texts = [ - "华东师范大学是综合性研究型大学。", - "量子计算是计算科学的前沿领域。", -] - -if not texts or not all(isinstance(text, str) for text in texts): - raise TypeError("input must be a non-empty string array") - -response = client.embeddings.create( - model="ecnu-embedding-small", - input=texts, -) - -ordered = sorted(response.data, key=lambda item: item.index) -vectors = [item.embedding for item in ordered] -if len(vectors) != len(texts): - raise RuntimeError("embedding response count did not match input count") -assert all(len(vector) == 1024 for vector in vectors) -``` - -Do not send integer token IDs. - -### LangChain embeddings - -```bash -python3 -m pip install langchain-openai -``` +Standalone example; requires `langchain-openai`: ```python +import os from langchain_openai import OpenAIEmbeddings embeddings = OpenAIEmbeddings( + api_key=os.environ["ECNU_API_KEY"], base_url="https://chat.ecnu.edu.cn/open/api/v1", - api_key=api_key, model="ecnu-embedding-small", check_embedding_ctx_length=False, timeout=60.0, max_retries=0, ) - -vector = embeddings.embed_query("Hello world") -assert len(vector) == 1024 +texts = ["Hello world", "Example document"] +if not texts or any(not isinstance(text, str) for text in texts): + raise ValueError("Expected a non-empty list of strings") +vectors = embeddings.embed_documents(texts) +if len(vectors) != len(texts) or any(len(vector) != 1024 for vector in vectors): + raise RuntimeError("Unexpected embedding count or vector length") +print(f"Received {len(vectors)} vectors") ``` -`check_embedding_ctx_length=False` prevents LangChain from converting strings -to OpenAI token IDs. Validate the fixed output size after the response; do not -send a dimension-selection request field that ECNU does not document. - -For many texts, use conservative sequential batches: - -```python -def chunks(items, size): - for start in range(0, len(items), size): - yield items[start : start + size] +For longer inputs, follow the current endpoint's character limit and split +locally. Do not infer an undocumented batch maximum from per-call billing. +When using direct HTTP, align vectors with inputs by their returned `index`. +## Thinking and tool history -all_vectors = [] -for batch in chunks(texts, size=16): # Application policy, not an ECNU limit. - response = client.embeddings.create( - model="ecnu-embedding-small", - input=batch, - ) - ordered = sorted(response.data, key=lambda item: item.index) - all_vectors.extend(item.embedding for item in ordered) -``` +Use the [ECNU thinking contract](https://developer.ecnu.edu.cn/vitepress/llm/thinking.html) +and the wire format of the chosen endpoint. For Chat Completions, enable +thinking through `thinking.type`; direct `reasoning_effort` uses `low`, `high`, +or `max` on `ecnu-max` and is ignored by `ecnu-plus`. Pass ECNU extensions through +`extra_body` with the OpenAI SDK. Do not substitute upstream template switches. -## Rerank +For a tool exchange, append the complete actual assistant message before the +matching tool results. ECNU documents preserving `reasoning_content` for +thinking-mode tool calls through subsequent user turns. Keep it only in process +memory. The [2026-09-12 observation](known_deviations.md#max-thinking-response-fields) +records varying returned fields: preserve what exists, do not fabricate a +missing field, and do not infer thinking was disabled from its absence. -The OpenAI SDK has no rerank resource, so use direct HTTP: +Integration fragment for an existing **direct-HTTP** loop; `assistant_message` +is the original response message, `tool_results` contains already validated, +authorized tool results, and each result has a matching call ID: ```python -import requests - -documents = [ - "华东师范大学是教育部直属的综合性研究型大学。", - "量子计算是计算科学的前沿领域。", -] -top_n = 2 - -if not documents or not all(isinstance(doc, str) for doc in documents): - raise TypeError("documents must be a non-empty string array") -if any(len(doc) > 8192 for doc in documents): - raise ValueError("each document must be at most 8192 characters") -if not 1 <= top_n <= len(documents): - raise ValueError("application policy requires a valid result count") - -response = requests.post( - "https://chat.ecnu.edu.cn/open/api/v1/rerank", - headers={ - "Authorization": f"Bearer {api_key}", - "Content-Type": "application/json", - }, - json={ - "model": "ecnu-rerank", - "query": "介绍华东师范大学", - "documents": documents, - "return_documents": True, - "top_n": top_n, - }, - timeout=60, -) -response.raise_for_status() +from copy import deepcopy -for result in response.json()["results"]: - print(result["index"], result["relevance_score"]) +messages.append(deepcopy(assistant_message)) +for call_id, result_text in tool_results: + messages.append({ + "role": "tool", + "tool_call_id": call_id, + "content": result_text, + }) +# Send this continuing history, and retain it for the next user turn. +# Do not print or persist reasoning_content, reasoning, or private tool output. ``` -The local `top_n` check is application policy, not a published ECNU maximum. +Only execute complete, validated tool arguments, not partial streamed JSON. +For SDKs/frameworks, check that serialization retains the fields needed for +continuation; do not blindly convert Responses or Anthropic blocks into Chat +roles. An endpoint smoke pass is not proof that a framework adapter works. -## Image generation +## Anthropic SDK -This call consumes credits. Do not run it merely to validate code. Use a -one-time URL only in memory and transfer the response to controlled storage -before its 24-hour expiry. +Use the [Anthropic-compatible contract](https://developer.ecnu.edu.cn/vitepress/llm/api/anthropic.html), +not the OpenAI root. Standalone example; requires `anthropic`: ```python import os -from pathlib import Path -from tempfile import NamedTemporaryFile -from urllib.parse import urlsplit - -import requests - -response = client.images.generate( - model="ecnu-image", - prompt="水墨风,竹林,渔船,湖泊,带斗笠的老翁", - size="1024x1024", - response_format="url", -) - -item = response.data[0] if response.data else None -image_url = getattr(item, "url", None) -if not image_url: - raise RuntimeError("image response contained no URL") - -approved_hosts = { - host.strip().lower() - for host in os.environ["APPROVED_IMAGE_HOSTS"].split(",") - if host.strip() -} -parsed_url = urlsplit(str(image_url)) -hostname = parsed_url.hostname -if parsed_url.scheme.lower() != "https" or not hostname or hostname.lower() not in approved_hosts: - raise RuntimeError("image URL host is not approved") - -target = Path(".live-artifacts") / "generated-image.bin" -target.parent.mkdir(parents=True, exist_ok=True) -temporary = None -max_image_bytes = 20 * 1024 * 1024 # Application policy, not an ECNU limit. -try: - try: - with requests.get( - str(image_url), stream=True, timeout=(5, 60), allow_redirects=False - ) as download: - if download.is_redirect: - raise RuntimeError("redirect target requires separate validation") - download.raise_for_status() - media_type = download.headers.get("Content-Type", "").split(";", 1)[0] - if not media_type.startswith("image/"): - raise RuntimeError("download did not return an image") - with NamedTemporaryFile("wb", dir=target.parent, delete=False) as output: - temporary = Path(output.name) - total = 0 - for block in download.iter_content(64 * 1024): - if not block: - continue - total += len(block) - if total > max_image_bytes: - raise RuntimeError("download exceeded the application limit") - output.write(block) - if total == 0: - raise RuntimeError("download returned an empty image") - except requests.RequestException: - raise RuntimeError("image download failed") from None - temporary.replace(target) -finally: - if temporary is not None and temporary.exists(): - temporary.unlink() -``` - -Do not print or log `image_url`. Configure `APPROVED_IMAGE_HOSTS` from an -application-owned egress policy and validate every redirect separately. Do not -retry generation after an ambiguous timeout. - -## Text-to-speech +from anthropic import Anthropic -This call consumes credits: - -```python -response = client.audio.speech.create( - model="ecnu-tts", - input="你好,欢迎使用文本转语音服务。", - voice="xiayu", - response_format="mp3", - speed=1.0, -) - -response.stream_to_file(".live-artifacts/output.mp3") -``` - -Multiple texts require separate sequential calls. They are not one batch API -request. - -## Structured output - -Both `ecnu-plus` and `ecnu-max` support this `json_schema` request. The -schema and JSON-object examples here follow the current documentation; -they are not included in the dated SDK live-verification claim above. - -```python -import json - -schema = { - "type": "object", - "properties": { - "name": {"type": "string"}, - "department": {"type": "string"}, - "title": {"type": "string"}, - }, - "required": ["name", "department", "title"], -} - -completion = client.chat.completions.create( - model="ecnu-plus", - messages=[ - { - "role": "system", - "content": "Extract name, department, and title.", - }, - { - "role": "user", - "content": "张三,法律事务部高级总监。", - }, - ], - response_format={ - "type": "json_schema", - "json_schema": { - "name": "info_extraction", - "schema": schema, - }, - }, - max_tokens=512, -) - -if not completion.choices or not completion.choices[0].message.content: - raise RuntimeError("structured response contained no content") -if completion.choices[0].finish_reason != "stop": - raise RuntimeError("structured response did not finish normally") -result = json.loads(completion.choices[0].message.content) -if not isinstance(result, dict) or not all( - isinstance(result.get(field), str) for field in schema["required"] -): - raise RuntimeError("structured response did not match the extraction schema") -print(result) -``` - -For JSON-object output without a supplied schema: - -```python -completion = client.chat.completions.create( - model="ecnu-max", - messages=[{"role": "user", "content": 'Return a JSON object with status "ok".'}], - response_format={"type": "json_object"}, - max_tokens=128, -) -if not completion.choices or completion.choices[0].finish_reason != "stop": - raise RuntimeError("JSON response did not finish normally") -content = completion.choices[0].message.content -if not content: - raise RuntimeError("JSON response contained no content") -result = json.loads(content) -if not isinstance(result, dict): - raise RuntimeError("JSON response was not an object") -print(result) -``` - -Do not strip Markdown fences before parsing. `json_object` does not guarantee -the `status` field or its value; validate application-specific requirements -separately. For more complex schemas, use a JSON Schema validator. - -## URL-parameter chat - -Build a link without navigating to it: - -```javascript -const question = "Hello"; -const url = `https://chat.ecnu.edu.cn/html/#/chat?submit=${encodeURIComponent(question)}`; -``` - -Opening `url` creates a new ChatECNU conversation and sends the question once, -after school SSO if needed. It is not an API call and takes no API key. Avoid -confidential questions in links that can be stored or shared. - -## Anthropic compatibility - -```bash -python3 -m pip install anthropic -``` - -```python -import os - -import anthropic - -anthropic_client = anthropic.Anthropic( +client = Anthropic( api_key=os.environ["ECNU_API_KEY"], base_url="https://chat.ecnu.edu.cn/open/api/anthropic", timeout=60.0, max_retries=0, ) - -message = anthropic_client.messages.create( +message = client.messages.create( model="ecnu-plus", - max_tokens=1000, - messages=[ - { - "role": "user", - "content": [{"type": "text", "text": "你好。"}], - } - ], -) - -text = "".join( - block.text - for block in message.content - if getattr(block, "type", None) == "text" + max_tokens=128, + messages=[{"role": "user", "content": "Reply with a short greeting."}], ) +text = "".join(block.text for block in message.content if block.type == "text") +if message.stop_reason != "end_turn" or not text: + raise RuntimeError("No complete text response; inspect the result before retrying") print(text) ``` -Use plain `ecnu-max` by default. Only try `ecnu-max[1m]` when an Anthropic tool -must recognize the long-context suffix: - -```python -def create_long_context_message( - client, messages, *, plain_max_previously_verified=False -): - try: - return client.messages.create( - model="ecnu-max[1m]", - max_tokens=1000, - messages=messages, - ) - except anthropic.AuthenticationError as exc: - if exc.status_code != 401 or not plain_max_previously_verified: - raise - return client.messages.create( - model="ecnu-max", - max_tokens=1000, - messages=messages, - ) -``` - -Use this one-shot fallback only after plain `ecnu-max` has already succeeded -with the same credential and the caller accepts losing the `[1m]` capability -signal. Log only that the fallback occurred, never the prompt, credential, or -error body. - -## Error handling - -Preserve JSON error structure, tolerate non-JSON errors, and retain only a -bounded, redacted sample plus an allowlisted request ID: - -```python -import json -import re - -SENSITIVE_KEYS = { - "authorization", "x_api_key", "api_key", "auth_token", "token", - "access_token", "client_secret", "ticket", "reasoning_content", "reasoning", - "messages", "input", "prompt", "content", "url", "download_url", - "image_url", "b64_json", "base64", "audio", "data", -} -SECRET_TEXT = re.compile( - r"(?i)(bearer\s+)[^\s\"']+|\bsk-[A-Za-z0-9_-]{8,}\b|" - r"https?://[^\s\"']+|data:[^,\s]+;base64,[A-Za-z0-9+/=_-]+" -) - - -def sanitize_error(value): - if isinstance(value, dict): - return { - str(key): ( - "[REDACTED]" - if str(key).lower().replace("-", "_") in SENSITIVE_KEYS - else sanitize_error(item) - ) - for key, item in value.items() - } - if isinstance(value, list): - return [sanitize_error(item) for item in value] - if isinstance(value, str): - return SECRET_TEXT.sub("[REDACTED]", value) - return value - - -def bounded_error_sample(response, limit=1000): - try: - value = response.json() - sample = json.dumps(sanitize_error(value), ensure_ascii=False) - except ValueError: - sample = SECRET_TEXT.sub("[REDACTED]", response.text) - return sample if len(sample) <= limit else sample[: limit - 14] + "...[truncated]" - - -def raise_ecnu_error(response): - if response.ok: - return - - request_id = next( - ( - response.headers.get(name) - for name in ("X-Request-ID", "Request-ID", "X-Trace-ID") - if response.headers.get(name) - ), - "unavailable", - ) - raise RuntimeError( - f"ECNU API HTTP {response.status_code} " - f"request_id={str(request_id)[:200]}: {bounded_error_sample(response)}" - ) -``` - -Do not retry unchanged credentials after `401`. For `422`, inspect field paths -and types. For `429`, stop concurrency, inspect credits, then use bounded -backoff. Do not blindly retry billable calls after an ambiguous timeout. +Use plain model names unless the caller actually requires the `[1m]` context +signal. Do not automatically treat a suffix-specific `401` as a bad key; follow +[the dated control/fallback conditions](known_deviations.md#anthropic-long-context-suffix-metadata). +Do not silently downgrade context or map unsupported effort values. diff --git a/references/models.md b/references/models.md index 635d37d..04b0579 100644 --- a/references/models.md +++ b/references/models.md @@ -1,267 +1,41 @@ -# ECNU Models, Credits, and Quotas +# Model and account pointers -Model and quota documentation and upstream background were checked on 2026-09-12. -Verify time-sensitive values against the official model and quota pages before -a production decision. This check is not a live API test. +Keep the user's working model unless they need selection help. For a new +ordinary text task, `ecnu-plus` is the local starting default; consider +`ecnu-max` for more demanding tasks. This is a practical starting point, not +a measured quality or latency ranking. -## Source precedence +## Find the current answer -1. Current model page: identity, context figures, aliases, and capabilities. -2. Endpoint page: request fields, types, and endpoint-specific limits. -3. Quota page: current prices, cache treatment, and quota periods. -4. Release notes: change dates. -5. `GET /models`: runtime visibility only. - -Upstream model cards and papers explain model design and serving techniques; -they do not override ECNU's hosted request fields, defaults, limits, or prices. - -## Primary dialog models - -| Model | Underlying model | Published context | Thinking | Tools | Vision | -|---|---|---|---|---|---| -| `ecnu-max` | DeepSeek-V4.1-Flash | 1M | Supported, default off | Yes | Yes | -| `ecnu-plus` | Qwen3.8-27B | 256K | Supported, default off | Yes | Yes | - -The model table does not label `1M` and `256K` as tokens or characters. Preserve -the published figures without adding a unit. The Anthropic page separately -describes `ecnu-max[1m]` as a 1M-character compatibility signal. - -Both models support image understanding through Chat Completions. Start with -`ecnu-plus` for lower-cost tasks; evaluate `ecnu-max` for complex text, code, -or visual reasoning. Measure task success and latency on ECNU. See -[Agent development](agent_development.md) for prompt and tool design. - -## Upstream model background - -The following is **`upstream-background`**, not an ECNU API guarantee. Use it -for model selection and diagnosing differences from upstream examples. - -### Qwen3.8-27B behind `ecnu-plus` - -The [Qwen model card](https://huggingface.co/Qwen/Qwen3.8-27B), also -[linked by ECNU on ModelScope](https://modelscope.cn/models/Qwen/Qwen3.8-27B), -describes a 27B dense vision-language model with improved coding and -long-horizon agentic capabilities. These are Qwen's claims, not ECNU benchmarks. - -| Upstream behavior | ECNU integration boundary | -|---|---| -| Native image and video understanding | ECNU documents image input on `ecnu-plus`, not a video request contract | -| 262,144-token native context, extendable to 1,000,000 through serving configuration such as YaRN | ECNU publishes 256K; do not enable a larger context by copying upstream flags | -| Thinking defaults on; effort defaults to `xhigh`, with `medium` and `low` also supported | ECNU defaults thinking off and ignores `reasoning_effort` on `ecnu-plus` | -| `preserve_thinking` defaults on to retain historical reasoning context | ECNU does not document this switch or `chat_template_kwargs`; preserve returned continuation fields only as required by the ECNU workflow | - -Qwen recommends `temperature=1.0, top_p=0.95` for thinking and -`temperature=0.7, top_p=0.8` for non-thinking in its own serving examples. -These are tuning starting points, not ECNU defaults. Do not copy upstream -`top_k`, `min_p`, or other undocumented controls into ECNU requests; sampling -controls may be restricted in ECNU thinking mode. - -### DeepSeek-V4.1-Flash behind `ecnu-max` - -The [DeepSeek model card](https://huggingface.co/deepseek-ai/DeepSeek-V4.1-Flash) -describes a multimodal MoE model with image and text input, text output, and -one-million-token context. Its Causal Encoder-Decoder architecture reduces -active computation during prefill, and its cache compression targets long, -input-heavy workloads. These are architectural motivations, not ECNU latency -or memory guarantees. - -| Upstream behavior | ECNU integration boundary | -|---|---| -| Continuous `reasoning_effort` from 1 to 100 | ECNU still documents `low`, `high`, `max`; do not send integers or invent a mapping | -| Agent benchmarks use `temperature=1.0`, `top_p=0.95` | Tuning candidates only; ECNU thinking mode may restrict sampling controls | -| Local inference recommends at least 256K output tokens | Not an ECNU output limit or an application default; budget each task | -| Custom prompt encoding and `deepseek-recipe` adapters | ECNU accepts structured API messages; do not inject upstream control tokens | - -The current ECNU model and Chat Completions pages both document vision. See -[dated live coverage](known_deviations.md#verified-coverage-on-2026-09-12) -for the tested image and protocol scope. - -### DSpark inference acceleration - -ECNU v3.3.0 announces DSpark support for `ecnu-max`. The -[DSpark paper](https://arxiv.org/abs/2607.05147) and -[DeepSeek's DeepSpec repository](https://github.com/deepseek-ai/DeepSpec) -describe speculative decoding: a lightweight draft module proposes token -blocks, and the target model verifies them, with confidence- and load-aware -verification scheduling. This is server-side decoding acceleration, not a -client-side instruction to reduce reasoning effort. - -DSpark is configured by the serving stack. ECNU documents no request-level -DSpark switch, new model ID, or -numerical speed guarantee. Keep using `ecnu-max`; do not invent `dspark: true`. -Gains depend on draft acceptance, workload, hardware, and serving load. The -paper's DeepSeek-serving benchmarks are not measurements of ECNU. When latency -matters, compare time to first token and generation speed with matched prompts, -output lengths, thinking settings, and load under an authorized test budget. - -## Compatibility aliases - -Prefer the primary names for new integrations. - -| Historical name | Effective behavior | -|---|---| -| `ecnu-reasoner` | `ecnu-max` with thinking enabled | -| `ecnu-reasoner-lite` | `ecnu-plus` with thinking enabled | -| `ecnu-turbo` | `ecnu-plus` | -| `ecnu-vl` | `ecnu-plus` | -| `InnoSpark` | `ecnu-plus` | -| `educhat-r1` | `ecnu-plus` | -| `educhat-general` | `ecnu-plus` | -| `educhat-psychology` | `ecnu-plus` | -| `ChatECNU` | `ecnu-plus` | -| `gpt-4` | `ecnu-plus` | - -Anthropic mappings are broader: `opus` maps to `ecnu-max`; `sonnet` and `haiku` -map to `ecnu-plus`; other unrecognized names map to `ecnu-plus`. - -These are internal compatibility-routing rules. The official Anthropic page -does not document whether the response `model` field echoes the requested alias -or identifies the effective ECNU model. - -## Model identifiers in responses - -A request model name selects a documented primary model or compatibility route; -it is not guaranteed to be echoed as the response label. Official Chat -Completions examples omit `model` in some responses and use a backend label in -others. Treat a returned `model` value as response metadata and do not require -equality with the requested name. The Anthropic response-label behavior is not -documented. - -## Specialized models - -| Model | Underlying model | Contract | -|---|---|---| -| `ecnu-embedding-small` | bge-m3 | Raw string or string array; documented input limit 8192 characters; 1024-float output | -| `ecnu-rerank` | bge-reranker-v2-m3 | String documents; 8192 characters per document | -| `ecnu-image` | Z-Image-Turbo | Prompt at most 1024 characters | -| `ecnu-tts` | Fun-CosyVoice3-0.5B | Input at most 4096 characters; 16 documented voices | - -The model page labels embedding and rerank context as `8K`, while endpoint pages -express request limits in characters. Use the endpoint wording when validating -requests. - -## Thinking mode - -Enable or disable dialog thinking with: - -```json -{"thinking":{"type":"enabled"}} -``` - -```json -{"thinking":{"type":"disabled"}} -``` - -For Chat Completions, `ecnu-max` accepts `reasoning_effort` values `low`, `high`, -or `max` when thinking is enabled. `ecnu-plus` ignores the field. - -Anthropic-compatible requests use `output_config.effort`: - -| Client value | `ecnu-max` tier | -|---|---| -| `minimal` | `low` | -| `low` | `low` | -| `medium` | `high` | -| `high` | `high` | -| `xhigh` | `high` | -| `max` | `max` | -| `none` | thinking disabled | - -Responses-compatible requests use `reasoning.effort` with the same -compatibility mapping. - -For thinking-mode assistant messages that call tools, ECNU requires retaining -`reasoning_content` in subsequent conversation history, including later user -turns. Keep it in process memory with the assistant/tool exchange; do not log -it or expose it to end users. See [Agent development](agent_development.md). -Returned reasoning fields may differ from the documented name; consult the -[live observation](known_deviations.md#max-thinking-response-fields) before -treating an absent `reasoning_content` field as proof that thinking was disabled. - -## Shared credits quotas - -The current official quota page documents these defaults for personal tokens: - -| Period | Shared default quota | -|---|---| -| Rolling 7 days | 20000 credits | - -All of a user's personal tokens share this pool. Only consumption within the -last 7 days counts; this is not a calendar-week reset. ChatECNU's left-side -**开放平台** entry shows the balance and window usage. There is no manual -quota-reset feature. When exhausted, reduce usage, wait for consumption to -leave the rolling window, or contact the platform about a suitable quota pool. - -Minute-level quota enforcement was reported as removed, but abnormal -high-frequency traffic may still trigger service protection. Recheck the quota -page before relying on these values. - -## Dialog credits - -Cached input is documented as costing one fifth of uncached input. - -| Model | Input miss | Input hit | Output or thinking | -|---|---|---|---| -| `ecnu-plus` | 100 credits / 1M tokens | 20 / 1M | 400 / 1M | -| `ecnu-max` | 300 credits / 1M tokens | 60 / 1M | 1200 / 1M | - -Do not assume a cache-hit ratio. ECNU's published examples use an assumption; -it is not a guarantee for an application. - -## Fixed-cost capabilities - -The current official quota page documents: - -| Capability | Model | Cost | -|---|---|---| -| Embedding | `ecnu-embedding-small` | 0.05 credits / call | -| Rerank | `ecnu-rerank` | 0.1 credits / call | -| Image generation | `ecnu-image` | 30 credits / successful generation | -| Text-to-speech | `ecnu-tts` | 5 credits / call | - -A per-call price does not define a supported batch size. Do not maximize a -batch based on billing alone. - -## Deployment and data handling - -The model page states that listed models are deployed locally and that data -processing normally occurs on campus servers. It also distinguishes -campus-specific applications such as ChatECNU and the Agent platform from -personal API service clusters. - -The security page explicitly allows temporary cloud-model fallback during -model upgrades, failures, or excessive load. Do not promise that requests -never leave campus; confirm the deployment path when data residency matters. - -The developer agreement makes the developer responsible for token protection, -lawful handling of personal information, downstream application behavior, and -rights to submitted inputs. It also states that de-identified input and output -may be used for service optimization, statistics, troubleshooting, and safety -risk control under the agreement's conditions. - -Before sending personal, confidential, or regulated information, verify that -the intended use and data-handling basis are appropriate. - -## Important changes - -| Date | Change | +| Question | Source | |---|---| -| 2026-09-12 documentation check | Current pages list DeepSeek-V4.1-Flash and image input for `ecnu-max`; exact rollout date is not stated | -| 2026-08-31 | v3.3.0: Qwen3.8-27B for `ecnu-plus`; DSpark for `ecnu-max`; rolling 7-day 20000-credit quota; dual-model structured-output fix; URL chat integration | -| 2026-08-10 | Reasoning-effort controls and compatibility mappings | -| 2026-08-09 | Security and developer-agreement documentation update | -| 2026-08-03 | TTS upgraded to Fun-CosyVoice3-0.5B; additional voices | -| 2026-08-01 | `ecnu-max` upgraded to DeepSeek-V4-Flash-0731 | -| 2026-04-24 | `ecnu-max` vision removal announced | -| 2026-04-03 | Dialog models consolidated to `ecnu-max` and `ecnu-plus` | -| 2025-03-20 | Native `search_mode` removed | - -## Official sources - -- https://developer.ecnu.edu.cn/vitepress/llm/model.html -- https://developer.ecnu.edu.cn/vitepress/llm/thinking.html -- https://developer.ecnu.edu.cn/vitepress/llm/limit.html -- https://developer.ecnu.edu.cn/vitepress/llm/release.html -- https://developer.ecnu.edu.cn/vitepress/llm/security.html -- https://developer.ecnu.edu.cn/vitepress/llm/tos.html -- https://chat.ecnu.edu.cn/status +| Supported model IDs, aliases, vision, context, underlying models | [Official model page](https://developer.ecnu.edu.cn/vitepress/llm/model.html) | +| Thinking switch and protocol-specific effort | [Thinking](https://developer.ecnu.edu.cn/vitepress/llm/thinking.html), then the chosen [endpoint](api_reference.md) | +| Token prices, fixed request costs, shared allowances, quota windows | [Current quota and pricing page](https://developer.ecnu.edu.cn/vitepress/llm/limit.html) | +| Obtain/configure credentials | [Authorization](https://developer.ecnu.edu.cn/vitepress/llm/authorization.html) | +| Residency, fallback, submitted data, retention, contractual requirements | [Data security](https://developer.ecnu.edu.cn/vitepress/llm/security.html) and [developer agreement](https://developer.ecnu.edu.cn/vitepress/llm/tos.html) | +| What changed and when | [Release notes](https://developer.ecnu.edu.cn/vitepress/llm/release.html) | +| Is there a reported incident? | [Service status](https://chat.ecnu.edu.cn/status) | + +## ECNU-specific boundaries + +Use primary ECNU model names for new integrations rather than upstream names +or historical aliases. A response's `model` metadata need not echo the requested +name. `/models` is runtime visibility, not a capability or authentication test. + +Upstream model cards can explain model design, but do not establish ECNU's +request fields, thinking defaults, context units, output limits, performance, +or deployment path. Do not copy upstream serving flags into requests. + +For a cost calculation, fetch current prices and show the input/output and +cache assumptions. Do not assume a cache-hit ratio or treat estimated usage as +verified account debit. A code-only task does not require a cost calculation. + +If current documentation is unavailable, do not invent current account values. +Continue independent implementation work with the relevant local recipe, +identify the unverified decision, and defer only what depends on that value. + +Historical model/Agent discussion remains in +[agent_development.md](agent_development.md) to preserve references from past +observations. It is not required reading for an ordinary integration and is +not a current model benchmark. diff --git a/references/workflows.md b/references/workflows.md index 6205633..d34e35f 100644 --- a/references/workflows.md +++ b/references/workflows.md @@ -1,348 +1,80 @@ -# Agent Workflows +# Targeted diagnosis and live checks -Use these procedures when implementing, reviewing, troubleshooting, or live -testing ECNU API integrations. +Use this reference for a failure or an explicitly needed verification, not +as a prerequisite for normal implementation. Fix the requested integration; +do not audit every endpoint or run repository-maintainer checks in a business +project. Preserve a working framework and make the smallest relevant change. -## Implementation workflow +## Start from the symptom -1. Identify the requested capability and protocol. -2. Read the relevant endpoint contract. -3. Select a primary model rather than a historical alias. -4. Build the smallest valid request. -5. Keep the API key in an environment variable. -6. Add explicit timeouts. -7. Validate the HTTP status, content type, and response shape. -8. Add advanced fields one at a time. -9. Keep calls sequential unless ECNU documents otherwise. -10. Report which behavior is documented and which is application policy. +Capture only the endpoint, model, SDK/version, status, content type, request ID, +and a bounded redacted error sample. Never capture credentials, private prompts, +or reasoning. Read the matching section below, not the entire deviation log. +These links are dated observations, not claims that the issue still reproduces. -Do not start from a generic OpenAI example and assume every field is supported. - -## Code-review checklist - -Check: - -- correct base URL and endpoint; -- correct model for the capability; -- environment-based credential loading; -- no key, ticket, or embedded URL in logs; -- documented JSON types; -- no OpenAI token-ID input for ECNU embeddings; -- no undocumented embedding dimension request; -- either primary model for Chat Completions image understanding; -- explicit timeout; -- SDK retries disabled with `max_retries=0` for live probes; -- bounded error-body capture; -- no automatic parallel batch; -- no blind retry for billable POST requests; -- output validation; -- privacy and data-minimization requirements. - -## Troubleshooting workflow - -### 1. Capture evidence - -Collect: - -- UTC timestamp; -- endpoint and method; -- model name; -- HTTP status; -- response content type; -- bounded, redacted body sample; -- request field names and JSON types; -- SDK and version, if applicable; -- whether the request was direct HTTP or an SDK call. - -Do not collect the API key or full sensitive prompt. - -### 2. Classify the failure - -| Symptom | First checks | +| Symptom | Check / relevant evidence | |---|---| -| `401` | credential source, expiry, protocol-specific auth handling | -| `403` | application or IP allowlist | -| `422` | missing field, wrong JSON type, unsupported request shape | -| `429` | credits, concurrent requests, burst protection | -| `5xx` JSON | proxy or backend error details | -| `5xx` plain text/HTML | preserve content type and bounded body | -| `200` with empty data | do not assume success; validate semantics | -| timeout or connection drop | mark inconclusive; the server may still have accepted the request | - -For quota-related `429` responses, check the shared rolling 7-day allowance in -[models.md](models.md). There is no manual quota reset. Reduce usage, wait for -older consumption to leave the window, or contact the platform for quota needs. - -### 3. Retry safely - -Safe GET requests may use limited exponential backoff with jitter. The live -validator never retries POST requests. - -Treat a POST timeout, connection drop, or truncated response as inconclusive. -Stop the flow and do not resubmit automatically; a later rerun is a new, -explicitly authorized request because the first request may have succeeded. - -For image generation, TTS, or any billed operation, do not automatically -resubmit after a timeout or connection drop unless the service provides an -idempotency mechanism or the user explicitly accepts duplicate charges. - -Never retry: - -- unchanged invalid credentials; -- a deterministic `422`; -- a rejected request shape; -- a known unsupported model. - -### 4. Compare sources - -Use this order: - -1. endpoint documentation; -2. model and quota pages; -3. dated known deviations; -4. a controlled live probe. - -Do not use a single `/models` result as proof of endpoint support. - -## Live-verification workflow - -Use `scripts/smoke_test.py`. Its default `auth` profile performs only service -status and model-list GET requests. The script uses fixed ECNU hosts, serial -requests, explicit timeouts, no POST retry, and a credit ceiling. - -Before opt-in POST probes: - -1. verify that existing account-owner authorization covers this test batch, - its data, ECNU destination, and purpose; ask only for missing or materially - changed coverage, preserving any explicit per-action approval; -2. verify the approved credit ceiling and cumulative expected batch use; - retain the default 50-credit ceiling and require separate authorization - before exceeding it, without resetting the allowance per request; -3. minimize prompts and output tokens; -4. remove personal or confidential data; -5. set an explicit timeout; -6. avoid parallel execution; -7. write only a sanitized structural report. - -The same approved batch does not require repeated confirmation. A pending -authorization blocks the affected live request; continue independent offline -preparation and checks within the existing scope. - -Create reports only under the ignored artifact directory. Model discovery and -the documented `401` expectations are non-billable: +| `200` with an empty model list | Not proof of authentication: [invalid bearer](known_deviations.md#invalid-bearer-on-model-discovery) | +| Missing auth produces an unexpected error | Preserve actual status and body type: [missing authorization](known_deviations.md#missing-authorization-on-model-discovery) | +| A new model ID appears but fails | Discovery is not endpoint capability: [runtime-only model](known_deviations.md#undocumented-model-visible-at-runtime) | +| `401` only for an unsupported model or `[1m]` | Compare a documented working control; do not rotate keys blindly: [unsupported model](known_deviations.md#unsupported-chat-model-error), [suffix conditions](known_deviations.md#anthropic-long-context-suffix-metadata) | +| SDK works for chat but embeddings fail | Check raw strings and local validation: [embedding recipe](examples.md#langchain-embeddings) | +| Tool continuation loses state or reasoning fields | Preserve the actual message and inspect serialization: [recipe](examples.md#thinking-and-tool-history), [field variation](known_deviations.md#max-thinking-response-fields) | +| TTS error parsing crashes | Tolerate non-JSON errors: [invalid voice](known_deviations.md#invalid-tts-voice-error-shape) | +| PCM bytes arrive without format metadata | Configure the format explicitly: [missing headers](known_deviations.md#successful-tts-response-headers) | +| Historical max-vision limitation conflicts with current docs | Check the chosen protocol and current contract: [resolved fixture](known_deviations.md#direct-ecnu-max-image-input) | +| `422` | Inspect `detail` and the relevant [request contract](api_reference.md); do not retry the unchanged request | +| `429` | Check [current credits/quota](models.md); stop parallel retries | +| Timeout or dropped connection after POST | Completion and debit may be unknown; do not automatically resubmit | + +A later release announcement does not by itself resolve a deviation. Do not +change observation dates or statuses without reproducing the affected behavior. + +## Run only the check needed + +If execution is not authorized or the key is absent, continue offline diagnosis +and provide the smallest runnable check. Do not repeatedly ask for authorization +already covering this account, data, destination, purpose, and cumulative budget. +New scope or an explicit per-action approval requirement still needs approval. + +For authorized live checks, use the existing `scripts/smoke_test.py` from the +installed skill's directory, not an assumed script in the user's application. +Check current prices first. The runner reads only `ECNU_API_KEY`, runs serially, +disables POST retries, reserves estimated credits, and redacts reports. Its +50-credit default is a cap, not authorization; use the lower approved cap and +obtain separate authorization before exceeding 50. Estimates are not actual debit. +Keep the same cumulative allowance across reruns, not a new allowance per process. + +To inspect options without a network request: ```bash -mkdir -p .live-artifacts -export ECNU_API_KEY="your-api-key" -python3 scripts/smoke_test.py --profile auth --max-credits 0 --timeout 30 \ - --account-type personal-token \ - --output .live-artifacts/auth.json +python3 scripts/smoke_test.py --help ``` -Exercise a valid-token gate, one invalid-token POST, and two request-shape -checks with a conservative allowance. These are real POST requests and require -account-owner authorization: +After approval for a model-list check and one SDK chat probe, with current +estimated cost within the approved allowance, an example targeted invocation is: ```bash -python3 scripts/smoke_test.py --profile core --max-credits 0.06 --timeout 60 \ - --case models_valid \ - --case error_invalid_token_post \ - --case error_missing_model \ - --case error_wrong_messages_type \ - --account-type personal-token \ - --output .live-artifacts/auth-and-422.json +python3 scripts/smoke_test.py --profile core --case models_valid --case openai_sdk_chat --max-credits 1 --output .live-artifacts/openai-sdk-chat.json ``` -The report stores the actual status and JSON shape even when the observed -service behavior differs from the documented `401` or `422` expectation. Do -not include `--strict` when the purpose is to collect deviation evidence. - -A valid report records: +The example ceiling is not a current price quote or spending permission. +Choose an actual case that answers the user's question. `auth` performs GET +checks only but is not conclusive authentication proof; `core`, `compatibility`, +and `billable` group other probes. Use `--case` to narrow them. Do not use `all` +for an ordinary integration check. Image/TTS probes need authorization covering +those billable operations and must not be scheduled automatically. -- test date and Python version; -- enabled profiles; -- status and content type per request; -- model IDs for `/models`; -- vector count and output length for embeddings; -- response structure, not successful model text or reasoning; -- bounded, redacted errors and allowlisted request IDs; -- transport errors as `inconclusive`, without credentials. +## Interpret the evidence -Interpret evidence per case: - -| `result` | Meaning | +| Runner result | Meaning | |---|---| -| `pass` | structural expectation passed in this dated run | -| `mismatch` | observed evidence differs from the documented expectation | -| `inconclusive` | no supportable endpoint conclusion, including transport failure | -| `skipped` | the case did not run and provides no live evidence | - -`classification: observed` is point-in-time evidence, not a platform -guarantee. Reproduce a mismatch before changing `known_deviations.md`; never -promote an inconclusive or skipped case into a claim. - -If the environment cannot reach the ECNU host, label the behavior unverified. -Do not update the known-deviation date. - -## Model-discovery workflow - -1. Read the model page for supported primary models and capabilities. -2. Call `/models` for runtime visibility. -3. Reject an empty list as inconclusive rather than authenticated success. -4. Ignore undocumented model IDs for production selection until a controlled - capability probe succeeds. -5. Record capability probes by endpoint, because one model ID may not work - across every endpoint. -6. Prefer documented primary names even when aliases are visible. - -The `auth` command above is the executable discovery flow. A `200` response -with an empty `data` array does not prove authentication. - -## Thinking-and-tool workflow - -A tool step spans two requests. Append the returned assistant message, including -its `reasoning_content`, before the matching tool result. Preserve that exchange -in subsequent history, including later user turns. Keep reasoning in process -memory only; never print it or write it to a report. Clear it when the whole -conversation ends. The isolated probe below ends after its second request; -an ongoing Agent conversation does not. See [Agent development](agent_development.md). - -```bash -python3 scripts/smoke_test.py --profile core --max-credits 1.2 --timeout 60 \ - --case models_valid \ - --case chat_thinking_tool_first \ - --case chat_thinking_tool_continue \ - --account-type personal-token \ - --output .live-artifacts/thinking-tool.json -``` - -The validator retains the first assistant message only in ephemeral run state, -submits one tool result, then clears that state before writing the sanitized -structural report. - -This probe checks the documented `reasoning_content` field strictly. If it -differs from the current response, consult the -[live field observation](known_deviations.md#max-thinking-response-fields) -and validate continuation with the complete actual message; a mismatch alone -does not mean that thinking or tool use is unavailable. - -## Structured-output workflow - -After authorization for these low-cost POST probes, check both primary models -with both documented formats. These cases deliberately request Markdown -fences in the prompt to test the documented constrained-decoding behavior: - -```bash -python3 scripts/smoke_test.py --profile core --max-credits 0.7 --timeout 60 \ - --case models_valid \ - --case structured_output_ecnu_plus \ - --case structured_output_ecnu_max \ - --case structured_output_json_object_ecnu_plus \ - --case structured_output_json_object_ecnu_max \ - --account-type personal-token \ - --output .live-artifacts/structured-output.json -``` - -Require a normally completed response and directly parse its raw content as -JSON. The schema cases check the fixture's required string fields and reject -extra fields; the JSON-object cases check only object structure. Do not repair -fences or judge factual extraction accuracy as part of the format contract. -The announced v3.3.0 fix alone is not proof of a live pass; keep old observation -dates unchanged until the affected behavior has been retested. - -## Embedding workflow - -1. Validate `input` as `str` or non-empty `list[str]`. -2. Reject integer arrays. -3. Keep batches conservative and sequential. -4. With LangChain, disable client-side OpenAI token conversion. -5. Do not send an undocumented dimension-selection field. -6. Sort returned items by `index`. -7. Assert that each returned vector has 1024 values. -8. Split or reduce a batch only after a meaningful validation or size error; - do not claim the resulting size is an ECNU maximum. - -## Anthropic workflow - -1. Use the Anthropic root, not the OpenAI root. -2. Read `ECNU_API_KEY` from the environment and pass it to the SDK; set an - explicit timeout and `max_retries=0`. -3. Prefer `ecnu-plus` or plain `ecnu-max`. -4. Use `ecnu-max[1m]` only when a tool requires the suffix to advertise long - context. -5. After plain `ecnu-max` was verified with the same credential, fall back once - on the known suffix-specific `401` and report the capability difference. -6. Do not generalize the suffix to OpenAI-compatible APIs. - -Probe the suffix and its plain-model control narrowly: - -```bash -python3 scripts/smoke_test.py --profile compatibility --max-credits 0.16 \ - --timeout 60 \ - --case models_valid \ - --case anthropic_max_1m \ - --case anthropic_max_1m_fallback_plain_max \ - --account-type personal-token \ - --output .live-artifacts/anthropic-1m.json -``` - -In application code, fall back once only when the `[1m]` request itself returns -the known suffix-specific `401`, plain `ecnu-max` was already verified with the -same credential, and the caller accepts losing the long-context capability -signal. Otherwise surface the error. - -## Budgeted billable workflow - -Select exact billable cases and set a ceiling equal to their conservative -planned cost. The script reserves budget before each request and stops before -the next case would exceed it. For example, after explicit authorization for a -5-credit TTS probe and a 30-credit image probe: - -```bash -python3 scripts/smoke_test.py --profile billable --max-credits 35 --timeout 60 \ - --case models_valid \ - --case tts_xiayu_pcm \ - --case image_generation_documented \ - --account-type personal-token \ - --output .live-artifacts/billable.json -``` - -The image case attempts a bounded, public-network-safe validation without -persisting its one-time URL or generated bytes. A rejected download target or -transport failure is `inconclusive`; the billable POST is not retried. - -## Security and privacy workflow - -- Do not request a key in chat when an environment variable or secret manager - can be used. -- If a key was exposed, recommend rotation. -- Do not send private documents, images, secrets, personal information, or - internal prompts without a clear user request and appropriate handling basis. -- Do not log embed tickets, one-time URLs, authorization headers, or raw - production prompts. -- Sanitize exception bodies because proxies may echo request details. -- Keep live-test artifacts out of version control. - -## Result format - -A useful report distinguishes: - -```text -Documented: -- ... - -Upstream background (not an ECNU guarantee): -- ... - -Observed on YYYY-MM-DD: -- ... - -Unverified or environment-limited: -- ... - -Recommended application policy: -- ... -``` - -This prevents application safeguards and one-time observations from being -mistaken for platform guarantees. +| `pass` | That case's checks passed in this dated environment, not universal task quality | +| `mismatch` | The observed response differs from the checked expectation | +| `inconclusive` | No supportable conclusion, including a transport failure | +| `skipped` | No request ran; no live evidence | + +Keep reports under ignored `.live-artifacts/`. Report what was actually run and +what remains unknown; a failed download does not authorize another paid generation. +For a suffix fallback, retain the exact working-control and consent conditions in +the linked deviation rather than silently downgrading the capability. From 6ae931171137c84302db40ddcc81f65cfc12f494 Mon Sep 17 00:00:00 2001 From: "J.Jason" <130959319+JJasonSun@users.noreply.github.com> Date: Sat, 12 Sep 2026 15:49:41 +0800 Subject: [PATCH 2/4] fix: make ECNU recipes directly usable and verify SDK history --- SKILL.md | 3 +- docs/skill-refactor-plan.md | 32 +++++++++++++++++ references/examples.md | 16 +++++++-- tests/test_repository_contracts.py | 57 ++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 4 deletions(-) diff --git a/SKILL.md b/SKILL.md index 146437e..e409eb7 100644 --- a/SKILL.md +++ b/SKILL.md @@ -54,7 +54,8 @@ Its full messages URL ends in `/open/api/anthropic/v1/messages`. | Task | Next resource | |---|---| | Chat, streaming, vision, Responses, JSON, rerank, images, TTS, or browser integration | [Official endpoint map](references/api_reference.md): open only the matching page | -| LangChain embeddings or Anthropic SDK setup | [Integration recipes](references/examples.md): read the matching section | +| LangChain embeddings | [Embedding recipe](references/examples.md#langchain-embeddings) | +| Anthropic SDK setup | [Anthropic recipe](references/examples.md#anthropic-sdk) | | Thinking and tool continuation | [Tool-history recipe](references/examples.md#thinking-and-tool-history) plus the linked ECNU contract | | Model choice, prices, quotas, or deployment questions | [Model and account pointers](references/models.md) | | An error, unexpected result, or requested live check | [Targeted diagnosis](references/workflows.md); consult only the matching dated deviation | diff --git a/docs/skill-refactor-plan.md b/docs/skill-refactor-plan.md index 9d2a69c..c4561b1 100644 --- a/docs/skill-refactor-plan.md +++ b/docs/skill-refactor-plan.md @@ -86,3 +86,35 @@ 合并由维护者决定。更换模型后遇到具体问题再调整,不预先维护所有模型矩阵。 未来若反复遇到同类障碍,再决定是否继续拆分历史资料或新增可执行工具。 + +## 本地离线验收(2026-09-12) + +环境:Codex CLI 0.153.4、当前常用的 `gpt-6-astra` / `medium`;Python 3.9.6、 +OpenAI 2.48.0、Anthropic 0.125.0、LangChain OpenAI 0.3.35、HTTPX 0.28.1。 +三个合成小项目各开独立会话,项目内 skill 链接指向本 PR 工作树,并禁用旧全局版。 +走查禁止联网、安装依赖和读取真实凭据;实际读取路径已核对,未覆盖全局安装。 + +| 任务 | 实际行为与结果 | 阻力与缺少的输入 | +|---|---|---| +| 普通 Python 接入 | 读取入口和官方导航,保留原函数,补 ECNU 地址、模型、超时和不自动重试;4 项离线测试通过 | 没有索要密钥或停下来确认;只生成代码不缺输入 | +| LangChain Embedding | 读取配方和已安装 SDK 实现;截获的请求保持原始字符串、不含 `dimensions`,校验返回数量和 1024 维;5 项离线测试通过 | 入口未直达章节,搜索连带读到了工具和 Anthropic 示例;配置没有缺项 | +| `/models` 空列表失败样例 | 读取诊断表、匹配的历史偏差和模型说明;`200` 空/非空列表都不作为鉴权成功证据;4 项离线测试通过 | 没有运行全量 smoke 或反复确认;进一步判断需脱敏请求信息及受保护接口的结果 | + +三次都没有执行 Skill 仓库维护流程;失败任务搜索了相关词,但没有读取完整偏差日志。 +应用改动和测试经本地复核,走查记录与合成项目未纳入 Skill 发布内容。 + +据此只做两处内容修正:Embedding 与 Anthropic 分别直达对应章节; +工具历史配方补 OpenAI SDK 的 `model_dump(mode="json", exclude_unset=True)` 写法, +避免使用者自行猜测如何保留扩展字段。对应的一项回归测试执行实际 Markdown 片段, +覆盖 `reasoning_content`、`reasoning`、两者均不存在三种合成响应,检查工具结果和 +后续用户轮次的序列化请求仍保留原始助手消息。 + +离线检查:67 项仓库单元测试、仓库验证器、`skills-ref`、Python 编译、Markdown +链接与锚点、代码块语法和 `git diff --check` 均通过。另以合成 HTTP 响应执行改写后的 +Chat、Embedding、工具历史、Anthropic 示例;API 检查期间禁用真实 socket/DNS。 +Embedding 的 `timeout` 实际映射为 `request_timeout=60.0`;当前 SDK 还会自动发送 +`encoding_format="base64"`,这里只确认请求序列化,没有证明当前 ECNU 服务接受该字段。 + +未做真实 ECNU 请求、扣费核对、服务端兼容性复测或跨模型效果比较。 +观察记录的日期与状态未改;新增导航已校验锚点,未重复三次 Agent 走查。 +这些结果只覆盖上述版本和合成条件,不表示所有 Agent 的使用效果都有提升。 diff --git a/references/examples.md b/references/examples.md index b9fe0c2..186266c 100644 --- a/references/examples.md +++ b/references/examples.md @@ -79,10 +79,20 @@ for call_id, result_text in tool_results: # Do not print or persist reasoning_content, reasoning, or private tool output. ``` +For an OpenAI SDK Chat Completions response, first obtain `assistant_message` +for the fragment above: + +```python +assistant_message = response.choices[0].message.model_dump( + mode="json", exclude_unset=True +) +``` + +This retains returned extension fields without adding absent optional fields. Only execute complete, validated tool arguments, not partial streamed JSON. -For SDKs/frameworks, check that serialization retains the fields needed for -continuation; do not blindly convert Responses or Anthropic blocks into Chat -roles. An endpoint smoke pass is not proof that a framework adapter works. +For other SDKs/frameworks, check their serialization; do not blindly convert +Responses or Anthropic blocks into Chat roles. An endpoint smoke pass is not +proof that a framework adapter works. ## Anthropic SDK diff --git a/tests/test_repository_contracts.py b/tests/test_repository_contracts.py index da63608..199e372 100644 --- a/tests/test_repository_contracts.py +++ b/tests/test_repository_contracts.py @@ -1,5 +1,7 @@ from __future__ import annotations +import json +import re import sys import tempfile import unittest @@ -97,6 +99,61 @@ def test_known_deviation_schema_and_status(self) -> None: class CurrentRepositoryContractsTest(unittest.TestCase): + def test_openai_tool_recipe_preserves_returned_fields(self) -> None: + import httpx + from openai import OpenAI + + text = (ROOT / "references/examples.md").read_text(encoding="utf-8") + section = text.split("## Thinking and tool history\n", 1)[1].split("\n## ", 1)[0] + history_code, sdk_code = re.findall(r"```python\n(.*?)\n```", section, re.S) + for extension in ({"reasoning_content": "synthetic"}, {"reasoning": {"value": "synthetic"}}, {}): + with self.subTest(fields=list(extension)): + original = { + "role": "assistant", "content": None, + "tool_calls": [{ + "id": "call_test", "type": "function", + "function": {"name": "echo", "arguments": '{"text":"ping"}'}, + }], + **extension, + } + requests = [] + + def respond(request): + requests.append(json.loads(request.content)) + return httpx.Response(200, json={ + "id": "test-completion", "object": "chat.completion", "created": 0, + "model": "ecnu-max", "choices": [{ + "index": 0, + "finish_reason": "tool_calls" if len(requests) == 1 else "stop", + "message": original if len(requests) == 1 else { + "role": "assistant", "content": "ping", + }, + }], + }) + + with OpenAI( + api_key="test-key", base_url="https://example.test/v1", + http_client=httpx.Client(transport=httpx.MockTransport(respond)), + max_retries=0, + ) as client: + messages = [{"role": "user", "content": "Echo ping"}] + response = client.chat.completions.create(model="ecnu-max", messages=messages) + namespace = {"response": response, "messages": messages, + "tool_results": [("call_test", "ping")]} + exec(sdk_code, namespace) + exec(history_code, namespace) + response = client.chat.completions.create(model="ecnu-max", messages=messages) + messages.append(response.choices[0].message.model_dump(mode="json", exclude_unset=True)) + messages.append({"role": "user", "content": "What was the tool result?"}) + client.chat.completions.create(model="ecnu-max", messages=messages) + + self.assertEqual(namespace["assistant_message"], original) + for request in requests[1:]: + self.assertEqual(request["messages"][1], original) + self.assertEqual(request["messages"][2], { + "role": "tool", "tool_call_id": "call_test", "content": "ping", + }) + def test_agents_repository_guide_contract(self) -> None: text = (ROOT / "AGENTS.md").read_text(encoding="utf-8") self.assertEqual(validate_skill.validate_agents_text(text), []) From d6e38a4b3b1df401270e14555d467e03ec2f5b21 Mon Sep 17 00:00:00 2001 From: "J.Jason" <130959319+JJasonSun@users.noreply.github.com> Date: Sat, 12 Sep 2026 16:03:14 +0800 Subject: [PATCH 3/4] docs: record live validation of ECNU integration recipes --- docs/skill-refactor-plan.md | 23 +++++++++++++++++++--- references/examples.md | 5 +++-- references/known_deviations.md | 36 ++++++++++++++++++++++++++++++---- 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/docs/skill-refactor-plan.md b/docs/skill-refactor-plan.md index c4561b1..01318c7 100644 --- a/docs/skill-refactor-plan.md +++ b/docs/skill-refactor-plan.md @@ -18,12 +18,12 @@ | `README.md`、`AGENTS.md` | 区分使用者与维护者,提供接续入口 | 业务项目不运行 Skill 仓库的维护命令 | 保留 `scripts/`、`tests/` 和 CI,不重写已有测试工具。 -保留 `known_deviations.md` 的全部原始记录、日期与状态。 +保留 `known_deviations.md` 的原始记录,只为实际复测的行为追加日期和证据。 保留 `agent_development.md`,因为旧实测记录引用其中的具体提示词; 它退出默认接入路径,但不在此次改版中删除历史证据的来源。 -本 PR 不运行真实 ECNU 请求,不新增 SDK、不新增评测平台,不自动合并。 -代码示例的改写不代表这些新文本已做实网复测。 +真实 ECNU 请求仅在另有明确授权时执行;不新增 SDK、不新增评测平台,不自动合并。 +代码示例的改写本身不代表实网复测,实际检查范围记录在下方验收结果中。 ## 本地 Codex 接续 @@ -118,3 +118,20 @@ Embedding 的 `timeout` 实际映射为 `request_timeout=60.0`;当前 SDK 还 未做真实 ECNU 请求、扣费核对、服务端兼容性复测或跨模型效果比较。 观察记录的日期与状态未改;新增导航已校验锚点,未重复三次 Agent 走查。 这些结果只覆盖上述版本和合成条件,不表示所有 Agent 的使用效果都有提升。 + +## 获授权后的实网验收(2026-09-12) + +在上述离线走查之后,使用用户提供并明确授权的令牌完成 8 个串行请求(6 POST、2 GET), +每个请求只执行一次。直接执行本分支示例与 SDK 工具历史片段,记录脱敏结果: + +- Python 与 Anthropic SDK 示例正常完成。 +- LangChain 原始字符串请求被接受,包括 SDK 自动添加的 `encoding_format="base64"`; + 未发送 `dimensions`,返回两个 1024 维向量。 +- Max `low` 思考模式的工具首轮返回 `reasoning_content`;SDK 转换保留完整原消息, + 工具结果续接及后续用户轮次均正常返回预期值。 +- 有效令牌返回模型列表;无效令牌仍返回 `200` 空列表,复现已有鉴权偏差。 + +本轮按 usage 与当前官方单价估算消耗 0.43764 Credits;包含此前测试的累计预留为 +44.29 / 50 Credits,累计估算消耗 3.92822 Credits,未核对账号实际扣减。 +详见[带版本与范围的实测记录](../references/known_deviations.md#verified-recipe-coverage-on-2026-09-12)。 +没有改动接入配置;仅更新已复测证据。其他历史样例、跨版本/跨模型效果仍未复测。 diff --git a/references/examples.md b/references/examples.md index 186266c..fe21a56 100644 --- a/references/examples.md +++ b/references/examples.md @@ -8,8 +8,9 @@ the [official page](api_reference.md). The executable examples below make real requests when run. Use the project's existing environment and dependencies; do not install or run them for a code-only request. Live execution follows the authorization and budget boundary -in the skill. Rewritten snippets are not new live-verification evidence; -[dated observations](known_deviations.md) retain their original scope and dates. +in the skill. Checked versions and scope are recorded in the +[dated recipe coverage](known_deviations.md#verified-recipe-coverage-on-2026-09-12); +an example edit alone does not refresh that evidence. ## LangChain embeddings diff --git a/references/known_deviations.md b/references/known_deviations.md index a046ab4..2410d53 100644 --- a/references/known_deviations.md +++ b/references/known_deviations.md @@ -16,16 +16,22 @@ Requests were serial with no POST retries and a cumulative 50-credit ceiling. Only synthetic text and PNG inputs were used. Prompts, generated content, reasoning text, and credentials were not retained in reports. +Test environment `live-2026-09-12-b` checked the PR #3 recipes with the same +macOS/Python environment, OpenAI 2.48.0, Anthropic 0.125.0, +langchain-openai 0.3.35, and httpx 0.28.1. Requests used synthetic text, +60-second timeouts, no retries, and the same cumulative 50-credit ceiling. +Only response structure, field-preservation checks, and usage were retained. + ## Invalid bearer on model discovery -- **Tested at:** 2026-08-23 -- **Environment:** live-2026-08-23-a, direct HTTP +- **Tested at:** 2026-08-23; reproduced 2026-09-12 +- **Environment:** live-2026-08-23-a, direct HTTP; live-2026-09-12-b, HTTPX - **Protocol and endpoint:** OpenAI-compatible `GET /models` - **Documented expectation:** Missing or invalid authentication returns `401`. - **Observed behavior:** An obviously invalid bearer returned `200` JSON with an empty model list. - **Reproduction conditions:** Send `GET /models` with a non-secret invalid bearer value. - **Impact:** An empty list can be mistaken for authenticated discovery. -- **Recommended fallback:** Require a non-empty valid-token list; do not use an empty list as an auth check. +- **Recommended fallback:** Treat discovery as model visibility, not authentication proof; check authenticated access with a protected documented endpoint. - **Status:** active ## Missing authorization on model discovery @@ -260,7 +266,7 @@ proves or disproves internal routing. ## Verified coverage on 2026-09-12 -The targeted update made 30 requests: 24 passed their checks, five differed +Environment `live-2026-09-12-a` made 30 requests: 24 passed their checks, five differed from expectations, and one timed out. The five mismatches were the four canonical reasoning-field checks described above and the truncated plus image probe. The latter was followed by a normally completed image check with more @@ -299,6 +305,28 @@ Response model metadata included `qwen3.6-plus`, `deepseek-v4-flash`, and alone do not establish the deployed model identity or contradict its documented routing; do not silently replace the documented model table with them. +## Verified recipe coverage on 2026-09-12 + +Environment `live-2026-09-12-b` made eight requests: six POSTs and two GETs. +Seven passed their checks; the invalid-bearer GET reproduced the `200` empty-list +deviation above. Every request had exactly one transport attempt. + +- The exact Python Chat and Anthropic SDK snippets returned normally completed text. +- The LangChain snippet sent both original strings, omitted `dimensions`, and + included the SDK's automatic `encoding_format="base64"`. The service accepted + this request and returned two 1024-value vectors. +- Max thinking at `low` returned an echo tool call with `reasoning_content`. + The SDK recipe's dictionary equaled the original response message. The tool + result and later user turn both preserved that original message on the wire + and returned the expected value with normal completion. + +This batch's usage-based estimate was 0.43764 credits under the +[current pricing formula](https://developer.ecnu.edu.cn/vitepress/llm/limit.html). +The cumulative reservation, including earlier checks, was 44.29 credits; +estimated cumulative consumption was 3.92822 credits. Neither is verified +account debit. This targeted run does not revalidate other historical cases, +other SDK versions, streaming, or arbitrary framework adapters. + ## Update rules 1. Record the date, non-secret environment, protocol, endpoint, expectation, From 27cb51499f0cb29ecf1a277b82e2fb539dc948b3 Mon Sep 17 00:00:00 2001 From: "J.Jason" <130959319+JJasonSun@users.noreply.github.com> Date: Sat, 12 Sep 2026 16:53:36 +0800 Subject: [PATCH 4/4] docs: close refactor handoff and align maintenance guidance --- AGENTS.md | 2 +- README.md | 2 +- docs/skill-refactor-plan.md | 153 ++++++-------------------------- references/agent_development.md | 6 +- references/known_deviations.md | 9 +- 5 files changed, 39 insertions(+), 133 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 93de1a7..ca5aeab 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -16,7 +16,7 @@ These instructions apply to maintaining this repository, not consuming apps. - `references/known_deviations.md`: dated live evidence; preserve dates and scope. - `references/agent_development.md`: historical guidance cited by old observations. - `scripts/` and `tests/`: existing diagnostics and offline validation. -- `docs/skill-refactor-plan.md`: scope, local handoff, and acceptance checks. +- `docs/skill-refactor-plan.md`: refactor scope and acceptance evidence. ## Editing rules diff --git a/README.md b/README.md index 7740ab7..ed3f10d 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ credentials should not prevent the Agent from writing or reviewing code. | Diagnose a failure or select a live probe | [Targeted diagnosis](references/workflows.md) | | Inspect dated evidence | [Known deviations](references/known_deviations.md) | | Maintain this repository | [AGENTS.md](AGENTS.md) | -| Continue this simplification locally | [Implementation and handoff plan](docs/skill-refactor-plan.md) | +| Inspect the refactor's acceptance evidence | [Acceptance record](docs/skill-refactor-plan.md) | The older [Agent-development notes](references/agent_development.md) remain to preserve historical prompt-fixture references in the observation log. They are diff --git a/docs/skill-refactor-plan.md b/docs/skill-refactor-plan.md index 01318c7..21980f2 100644 --- a/docs/skill-refactor-plan.md +++ b/docs/skill-refactor-plan.md @@ -1,137 +1,40 @@ -# ECNU Skill 实用化改版与本地接续计划 +# ECNU Skill 实用化改版验收 -## 目标 +改版目标是减少重复配置、文档查找和兼容性误判。日常接入从 +[SKILL.md](../SKILL.md) 开始;官方契约、针对性配方、历史偏差和仓库维护各有入口。 +本文件保留改版的验收证据,原接续步骤已经完成,不是下一次使用的待办清单。 -让用户少交代 ECNU 背景,让 Agent 少找资料、少猜兼容性、少重复写接入逻辑。 -不是追求最短文件、完整复制官网,也不是搭建跨模型评测平台。 -默认路径应当支持普通任务直接开始;只有任务需要时才进入详细排障或真实验证。 +## 2026-09-12 离线验收 -## 本 PR 的范围 - -| 文件 | 改动 | 验收边界 | -|---|---|---| -| `SKILL.md` | 九步通用流程改为最小接入、任务导航、执行边界 | 写代码不需要密钥,不强制全量 smoke 或固定报告 | -| `references/api_reference.md` | 参数表副本改为官方接口导航 | 原有能力仍有官方入口,不让用户自己找链接 | -| `references/models.md` | 保留默认选择与账号来源,移除价格/配额和上游架构副本 | 不把旧数值或上游能力当作当前 ECNU 契约 | -| `references/examples.md` | 聚焦 Embedding、工具历史、Anthropic 三个接入配方 | 不复制整套 SDK;工具代码片段明确前置条件 | -| `references/workflows.md` | 按症状找证据,按需选择最小验证 | 保留授权、预算、脱敏、串行和不盲重试边界 | -| `README.md`、`AGENTS.md` | 区分使用者与维护者,提供接续入口 | 业务项目不运行 Skill 仓库的维护命令 | - -保留 `scripts/`、`tests/` 和 CI,不重写已有测试工具。 -保留 `known_deviations.md` 的原始记录,只为实际复测的行为追加日期和证据。 -保留 `agent_development.md`,因为旧实测记录引用其中的具体提示词; -它退出默认接入路径,但不在此次改版中删除历史证据的来源。 - -真实 ECNU 请求仅在另有明确授权时执行;不新增 SDK、不新增评测平台,不自动合并。 -代码示例的改写本身不代表实网复测,实际检查范围记录在下方验收结果中。 - -## 本地 Codex 接续 - -在本 PR 分支继续,先检查工作区,不覆盖本地未提交改动。 -先读 `AGENTS.md`、本计划和 diff,不需要重新研究整个 Agent Skills 体系。 - -### 1. 完成常规离线检查 - -运行 `AGENTS.md` 中的验证、单元测试、编译、格式检查。 -参考格式验证器不可用时如实记录,不为它阻塞独立工作。 -检查 Markdown 相对链接、章节锚点和示例代码;不执行示例里的网络请求。 -尤其确认依赖版本下的 Embedding 参数和 SDK 消息序列化行为。 -修复真实问题,不新增长篇原则,也不为迎合旧目录结构削弱安全检查。 - -### 2. 用三个日常请求走查,不做模型矩阵 - -在平时使用的 Agent/模型环境中,开启独立任务会话,使用本分支材料。 -确认加载的不是旧全局安装版;不要手工覆盖已安装的 skill 目录。 -走查时不读取、复制或提交真实凭据,默认只写代码或使用合成响应。 - -| 请求 | 看什么 | -|---|---| -| 给现有 Python 项目接 ECNU,只生成代码 | 是否直接开始,是否找对相关文档,有无无关阅读和多余流程 | -| 把现有 LangChain Embedding 改为 ECNU | 实际请求是否保持原始字符串,而不只是答案中提到配置 | -| 给出一个失败样例,例如 `/models` 返回空列表 | 是否给出针对性诊断,而非全量测试、武断鉴权结论或反复确认 | - -不要求每个任务重复多次、不打综合分。简短记录“还需要我补充什么”以及 -“Skill 让 Agent 多做了什么”。若使用 mock,结论只能覆盖 mock 条件。 -一次真实使用没有暴露问题,不等于证明所有模型或所有任务都已覆盖。 - -### 3. 只围绕实际阻力补充 - -| 发现 | 优先处理 | -|---|---| -| Agent 不知道去哪查 | 修正对应文档入口 | -| 反复猜错 ECNU 特有配置 | 在对应配方补最小说明 | -| 重复实现同一段稳定代码 | 优先改现有样例;确认反复使用后再考虑脚本 | -| 因 Skill 读取无关材料或过度检查 | 缩小触发条件,删除或下沉要求 | -| 仅一次通用推理失误 | 先不加永久规则,避免为每次失误堆提示词 | - -至少确认有价值的配方仍容易找到,不能为了缩短行数删掉必要约束。 -没有实际阻力就停止,不为“补充”而补充。 - -## 只有确有必要时才做真实验证 - -真实请求需要账号、数据、目的和预算范围内的授权。 -在同一范围内复用授权;超范围、超预算或明确要求逐次审批时再确认。 -按当前价格选择一个相关 case,不跑 `all`,不顺带生成图片或语音。 -保留现有脚本的默认预算上限和更低的用户批准额度,跨次运行累计计算。 -脱敏结果留在忽略目录;只有实际复现后才修改对应观察记录。 - -## 合并前验收 - -- 普通代码请求能推进,不因缺密钥或不能实网验证而停止独立工作。 -- 官方导航覆盖原有主要能力;价格和模型表不再多处手工同步。 -- 接入配方、历史偏差、维护流程各有入口,不默认全部加载。 -- 当前文档、历史观察、本地默认策略没有混成同一种保证。 -- 原有离线测试和安全边界保留;实际未执行的检查明确标注。 -- 用本地实际任务确认没有明显新增阻力;这不是跨模型效果承诺。 - -合并由维护者决定。更换模型后遇到具体问题再调整,不预先维护所有模型矩阵。 -未来若反复遇到同类障碍,再决定是否继续拆分历史资料或新增可执行工具。 - -## 本地离线验收(2026-09-12) - -环境:Codex CLI 0.153.4、当前常用的 `gpt-6-astra` / `medium`;Python 3.9.6、 +环境:Codex CLI 0.153.4、`gpt-6-astra` / `medium`、Python 3.9.6, OpenAI 2.48.0、Anthropic 0.125.0、LangChain OpenAI 0.3.35、HTTPX 0.28.1。 -三个合成小项目各开独立会话,项目内 skill 链接指向本 PR 工作树,并禁用旧全局版。 -走查禁止联网、安装依赖和读取真实凭据;实际读取路径已核对,未覆盖全局安装。 - -| 任务 | 实际行为与结果 | 阻力与缺少的输入 | -|---|---|---| -| 普通 Python 接入 | 读取入口和官方导航,保留原函数,补 ECNU 地址、模型、超时和不自动重试;4 项离线测试通过 | 没有索要密钥或停下来确认;只生成代码不缺输入 | -| LangChain Embedding | 读取配方和已安装 SDK 实现;截获的请求保持原始字符串、不含 `dimensions`,校验返回数量和 1024 维;5 项离线测试通过 | 入口未直达章节,搜索连带读到了工具和 Anthropic 示例;配置没有缺项 | -| `/models` 空列表失败样例 | 读取诊断表、匹配的历史偏差和模型说明;`200` 空/非空列表都不作为鉴权成功证据;4 项离线测试通过 | 没有运行全量 smoke 或反复确认;进一步判断需脱敏请求信息及受保护接口的结果 | +三个合成项目分别使用独立会话和本分支 Skill,禁用旧全局版及网络请求。 -三次都没有执行 Skill 仓库维护流程;失败任务搜索了相关词,但没有读取完整偏差日志。 -应用改动和测试经本地复核,走查记录与合成项目未纳入 Skill 发布内容。 +| 任务 | 检查结果 | +|---|---| +| 普通 Python 接入 | 保留原函数,配置 ECNU 地址、模型、超时和不自动重试;4 项离线测试通过 | +| LangChain Embedding | 实际请求保留原始字符串,不发送 `dimensions`;数量与 1024 维检查通过,共 5 项测试 | +| `/models` 空列表失败样例 | `200` 空/非空列表都不作为鉴权成功证据;4 项离线测试通过 | -据此只做两处内容修正:Embedding 与 Anthropic 分别直达对应章节; -工具历史配方补 OpenAI SDK 的 `model_dump(mode="json", exclude_unset=True)` 写法, -避免使用者自行猜测如何保留扩展字段。对应的一项回归测试执行实际 Markdown 片段, -覆盖 `reasoning_content`、`reasoning`、两者均不存在三种合成响应,检查工具结果和 -后续用户轮次的序列化请求仍保留原始助手消息。 +三次均未索要密钥、反复确认或执行平台全量 smoke、Skill 仓库维护流程。 +Embedding 与 Anthropic 入口分别直达对应章节;新增导航只校验了链接,未重复 Agent 会话。 +OpenAI SDK 工具消息转换配方由一项回归测试覆盖:完整保留 `reasoning_content`、 +`reasoning` 或两者均不存在时的实际返回字段,并检查工具结果和后续用户轮次。 -离线检查:67 项仓库单元测试、仓库验证器、`skills-ref`、Python 编译、Markdown -链接与锚点、代码块语法和 `git diff --check` 均通过。另以合成 HTTP 响应执行改写后的 -Chat、Embedding、工具历史、Anthropic 示例;API 检查期间禁用真实 socket/DNS。 -Embedding 的 `timeout` 实际映射为 `request_timeout=60.0`;当前 SDK 还会自动发送 -`encoding_format="base64"`,这里只确认请求序列化,没有证明当前 ECNU 服务接受该字段。 +67 项仓库测试、仓库验证器、`skills-ref`、Python 编译、Markdown 链接与锚点、 +代码块语法和 `git diff --check` 通过。维护命令见 [AGENTS.md](../AGENTS.md)。 -未做真实 ECNU 请求、扣费核对、服务端兼容性复测或跨模型效果比较。 -观察记录的日期与状态未改;新增导航已校验锚点,未重复三次 Agent 走查。 -这些结果只覆盖上述版本和合成条件,不表示所有 Agent 的使用效果都有提升。 +## 2026-09-12 实网验收 -## 获授权后的实网验收(2026-09-12) +获授权后直接执行本分支示例和工具历史片段,完成 8 个串行请求(6 POST、2 GET), +每个请求只执行一次。Python、LangChain Embedding、Anthropic 和 Max 工具三轮续接通过; +无效令牌的 `/models` 请求复现 `200` 空列表偏差。 -在上述离线走查之后,使用用户提供并明确授权的令牌完成 8 个串行请求(6 POST、2 GET), -每个请求只执行一次。直接执行本分支示例与 SDK 工具历史片段,记录脱敏结果: +版本、实际请求字段、返回形状及费用估算以 +[实测记录](../references/known_deviations.md#verified-recipe-coverage-on-2026-09-12) 为准。 -- Python 与 Anthropic SDK 示例正常完成。 -- LangChain 原始字符串请求被接受,包括 SDK 自动添加的 `encoding_format="base64"`; - 未发送 `dimensions`,返回两个 1024 维向量。 -- Max `low` 思考模式的工具首轮返回 `reasoning_content`;SDK 转换保留完整原消息, - 工具结果续接及后续用户轮次均正常返回预期值。 -- 有效令牌返回模型列表;无效令牌仍返回 `200` 空列表,复现已有鉴权偏差。 +## 验证边界 -本轮按 usage 与当前官方单价估算消耗 0.43764 Credits;包含此前测试的累计预留为 -44.29 / 50 Credits,累计估算消耗 3.92822 Credits,未核对账号实际扣减。 -详见[带版本与范围的实测记录](../references/known_deviations.md#verified-recipe-coverage-on-2026-09-12)。 -没有改动接入配置;仅更新已复测证据。其他历史样例、跨版本/跨模型效果仍未复测。 +这些结果只覆盖所列版本、合成输入与任务,不构成跨 Agent、跨模型或任意框架的效果承诺。 +账号实际扣减未核对;其他历史样例没有因本次检查而更新日期或状态。 +新增场景出现具体障碍时再补对应配方或检查,不预先扩展模型矩阵和通用教程。 diff --git a/references/agent_development.md b/references/agent_development.md index be0c605..36a302d 100644 --- a/references/agent_development.md +++ b/references/agent_development.md @@ -1,7 +1,9 @@ # Agent Development with ECNU Models -Use this reference for prompt design, tool loops, multimodal tasks, and Agent -evaluation. Sources were checked on 2026-09-12; this is not a live benchmark. +This historical reference preserves the prompt fixtures used in the +[2026-09-12 checks](known_deviations.md#verified-coverage-on-2026-09-12). +For current integration work, start with [SKILL.md](../SKILL.md). +Sources below were checked on 2026-09-12; this is not a current benchmark. Model facts and protocol rules are linked from [models.md](models.md) and [api_reference.md](api_reference.md). The design advice and prompt examples below are **`application-policy`**: starting points to evaluate on your tasks. diff --git a/references/known_deviations.md b/references/known_deviations.md index 2410d53..5713273 100644 --- a/references/known_deviations.md +++ b/references/known_deviations.md @@ -1,8 +1,9 @@ # Known Service Deviations -These entries are point-in-time observations, not official contracts. Preserve -the documented expectation in `api_reference.md`. Do not change a test date or -status unless the behavior was actually exercised again. +These entries are point-in-time observations, not official contracts. Keep each +entry's documented expectation separate from its observed result; current +contracts are linked from [api_reference.md](api_reference.md). Do not change a +test date or status unless the behavior was actually exercised again. Test environment `live-2026-08-23-a` was a personal token on macOS arm64 (Darwin 25.6.0), Python 3.9.6, OpenAI 2.48.0, Anthropic 0.125.0, @@ -338,5 +339,5 @@ other SDK versions, streaming, or arbitrary framework adapters. announced fix as a revalidation trigger, not as resolution evidence. 6. Recheck the current contract and pricing, then rerun only the affected cases with the current runner before changing dates, expectations, or statuses. -7. Require new account-owner authorization for billable revalidation; never +7. Require scoped account-owner authorization for billable revalidation; never schedule TTS or image-generation probes automatically.