Skip to content

Commit 240565f

Browse files
authored
Merge pull request #14 from huangy22/codex/lkm-api-contract-followup
docs(lkm): update search API contract guidance
2 parents a4ce5b2 + 49e6de2 commit 240565f

3 files changed

Lines changed: 105 additions & 48 deletions

File tree

en/bohrium-lkm/SKILL.md

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ description: "Large Knowledge Model (LKM) via open.bohrium.com (v1). Use when: u
77

88
## Overview
99

10-
LKM (Large Knowledge Model) v1 endpoints on `open.bohrium.com` let you search and trace knowledge extracted from scientific literature: search claim/question nodes, retrieve reasoning chains, view a paper-level knowledge graph, trace the reasoning behind a single claim, and batch-hydrate node details by ID.
10+
LKM (Large Knowledge Model) v1 endpoints on `open.bohrium.com` let you search and trace knowledge extracted from scientific literature: search claim/question/abstract knowledge hits, retrieve reasoning chains, view a paper-level knowledge graph, trace the reasoning behind a single claim, and batch-hydrate node details by ID.
1111

1212
**Core capabilities:**
1313

1414
| Endpoint | Function |
1515
|----------|----------|
16-
| `POST /v1/lkm/search` | Node search: recall relevant claim / question nodes |
16+
| `POST /v1/lkm/search` | Public search: recall claim / question / abstract hits; claim scopes may also target conclusion / premise roles |
1717
| `POST /v1/lkm/reasoning/search` | Reasoning chain search: recall whole chains by argument similarity |
1818
| `POST /v1/lkm/papers/graph` | Paper-level knowledge graph: full graph extracted from a paper |
1919
| `GET /v1/lkm/claims/{id}/reasoning` | Single-claim reasoning chain: why a claim holds |
@@ -22,7 +22,7 @@ LKM (Large Knowledge Model) v1 endpoints on `open.bohrium.com` let you search an
2222

2323
**Choosing an entry point:**
2424

25-
- Find claims/questions by keyword/semantics → `/search`
25+
- Find claims/questions/abstracts by keyword/semantics → `/search`
2626
- Find whole reasoning chains whose research/experimental process is similar (not just a single matching claim) → `/reasoning/search`
2727
- Open one paper and view its full structured graph → `/papers/graph`
2828
- Have a claim ID, want its reasoning chain → `/claims/{id}/reasoning`
@@ -48,7 +48,7 @@ The 5 retrieval endpoints fall into two groups:
4848

4949
> `/papers/graph` can be a standalone starting point if you already have a DOI or title; otherwise its `package_id`/`paper_id` typically comes from paper metadata returned by `/search` or `/reasoning/search`.
5050
51-
A search entry point's output (node IDs, paper IDs) is exactly the downstream input. Data flow:
51+
A search entry point's output (node IDs, paper IDs) is exactly the downstream input. `/search` defaults to paper aggregation: each main `variables[]` row is the representative hit for roughly one paper, and same-paper hits are folded into `related`. Abstract hits are paper-level background context; do not treat them as claims or reasoning roots.
5252

5353
```mermaid
5454
flowchart TD
@@ -127,26 +127,34 @@ The examples below call `lkm_data(r)` so the documented `code` contract is alway
127127

128128
---
129129

130-
## 1. Node search — `POST /search`
130+
## 1. Public search — `POST /search`
131131

132-
Recall claim / question nodes in LKM via natural language. Returns individual nodes, not full reasoning chains.
132+
Recall claim / question / abstract hits in LKM via natural language. By default, the server aggregates by paper and returns one representative main hit per paper, with additional same-paper hits in `related`. It returns hits and paper metadata, not full reasoning chains.
133133

134134
```python
135135
r = requests.post(f"{BASE}/search", headers=H, json={
136136
"query": "The 2017 chemistry curriculum standard increases emphasis on real‑world problem situations and contexts (explicitly including industrial production, environmental issues, and socio‑technical “hot topics”).",
137137
"keywords": ["real-world contexts", "industrial production", "inquiry learning"],
138138
"retrieval_mode": "hybrid",
139139
"sort_by": "comprehensive", # optional; default comprehensive; or relevance/recent/journal
140-
"scopes": ["claim", "question"],
141-
# "filters": {"paper_ids": ["811977903947382784"], "dois": ["10.1038/s41586-021-03381-x"]}, # optional; restrict recall to papers, ≤50 each
140+
"scopes": ["claim", "question", "abstract", "conclusion", "premise"],
141+
# "filters": {
142+
# "paper_ids": ["811977903947382784"], # plain numeric IDs, no paper: prefix
143+
# "dois": ["10.1038/s41586-021-03381-x"],
144+
# "title": "perovskite stability", # fuzzy title filter
145+
# "publication_date_start": "2020-01-01",
146+
# "publication_date_end": "2026-12-31",
147+
# "limit_publication_date": True, # default true; false also recalls undated papers
148+
# },
142149
"reasoning_only": False,
143150
"offset": 0,
144151
"limit": 20
145152
})
146153
data = lkm_data(r)
147154
for v in data["variables"]:
148155
print(v["id"], v["type"], v.get("role"), v["has_reasoning"], (v.get("content") or "")[:80])
149-
# data["papers"]: paper metadata referenced by hits (key like paper:<id>)
156+
# data["related"]: other relevant same-paper hits folded under the representative hit
157+
# data["papers"]: authoritative paper metadata referenced by hits (key like paper:<id>)
150158
# data["has_more"]: whether more pages exist
151159
```
152160

@@ -158,11 +166,14 @@ for v in data["variables"]:
158166
| `keywords` | string[] | no | Up to 10, ≤100 chars each; put terms/materials/methods/abbreviations, not full sentences |
159167
| `retrieval_mode` | string | no | `hybrid`(default, semantic+lexical) / `semantic`(vector only, faster) / `lexical`(keyword only) |
160168
| `sort_by` | string | no | Sort strategy, default `comprehensive` when omitted: `relevance`(pure relevance, most on-target top hit) / `recent`(prefers newer once relevance bar is met) / `journal`(prefers high-quality journals once relevance bar is met) / `comprehensive`(relevance+recency+quality+diversity combined) |
161-
| `scopes` | string[] | no | Restrict node type: `claim`, `question`; omit = no restriction |
169+
| `scopes` | string[] | no | Restrict hit scope: node types `claim` / `question` / `abstract`, or claim roles `conclusion` / `premise`; omit = no restriction |
162170
| `filters.visibility` | string | no | Content visibility, usually `public` |
163171
| `filters.role` | string | no | Restrict claim role: `conclusion`/`premise`/`highlight` |
164172
| `filters.paper_ids` | string[] | no | Restrict recall to papers, plain numeric IDs, **no `paper:` prefix**, up to 50 |
165-
| `filters.dois` | string[] | no | Restrict recall to papers by DOI, up to 50; server resolves each to a paper_id then merges with `paper_ids` for filtering; can be combined with `paper_ids`, omit = no paper restriction |
173+
| `filters.dois` | string[] | no | Restrict recall to papers by DOI, up to 50; can be combined with `paper_ids` |
174+
| `filters.title` | string | no | Fuzzy paper-title filter. When combined with `paper_ids` / `dois`, all dimensions are intersected (AND). Title filtering returns only the most relevant few papers by default and is not exhaustive. |
175+
| `filters.publication_date_start` / `filters.publication_date_end` | string | no | Publication-date bounds in `YYYY-MM-DD`; either side may be omitted |
176+
| `filters.limit_publication_date` | bool | no | Default `true`: apply the given date range; if both bounds are omitted, fall back to approximately the last 20 years. Set `false` to remove publication-date filtering entirely and recall undated papers. |
166177
| `reasoning_only` | bool | no | `true` returns only conclusion claims backed by a reasoning chain (legacy alias `evidence_only`) |
167178
| `include_paper_enrich` | bool | no | `true` returns richer paper metadata (larger response; use only when needed) |
168179
| `offset` | int | no | Page start, max 10000 |
@@ -172,16 +183,21 @@ for v in data["variables"]:
172183

173184
| Field | Description |
174185
|-------|-------------|
175-
| `data.variables[].id` | Global node ID (`gcn_...`), usable in later reasoning / batch calls |
176-
| `data.variables[].type` | `claim` or `question` |
177-
| `data.variables[].role` | Claim role: `conclusion`/`premise`, etc. |
178-
| `data.variables[].score` | Retrieval rank score — **not credibility/evidence strength**, do not show as confidence |
186+
| `data.variables[]` | Main result list after aggregation; each row is the representative hit for roughly one paper. `id` is the hit object ID. |
187+
| `data.variables[].type` | `claim`, `question`, or `abstract` |
188+
| `data.variables[].role` | Claim role: `conclusion` / `premise`, etc. |
189+
| `data.variables[].score` / `rerank_score` | Retrieval rank score — **not credibility/evidence strength**, do not show as confidence |
179190
| `data.variables[].has_reasoning` | Whether the claim has a traceable reasoning chain (prefer `true` when showing reasoning) |
180191
| `data.variables[].provenance.source_packages` | Source paper package IDs |
181-
| `data.papers` | Paper metadata map, key like `paper:<id>` |
192+
| `data.related` | Other relevant same-paper snippets folded under the main hit. This is same-paper context, not cross-paper recommendation and not the complete paper graph. |
193+
| `data.papers` | Authoritative paper metadata map, key like `paper:<id>`; use this for paper cards, DOI, journal, impact factor, etc. |
182194
| `data.has_more` | Whether more pages exist (next page: same body, `offset += page count`) |
183195

184-
**Constraint:** when `reasoning_only=true`, `scopes` must be omitted or `["claim"]`, and `filters.role` must be omitted or `conclusion`; conflicts return `290002`.
196+
**Constraints and policy:**
197+
198+
- `paper_ids`, `dois`, and `title` are intersected (AND). If any dimension resolves to no papers, the whole result is empty.
199+
- `abstract` hits are paper-level context for judging relevance or RAG background. Do **not** use them as claims and do not request reasoning chains from them.
200+
- When `reasoning_only=true`, `scopes` must be omitted or `["claim"]` / `["conclusion"]`, and `filters.role` must be omitted or `conclusion`; conflicts return `290002`.
185201

186202
> **Sorting note:** the recency/quality boosts in `recent`/`journal`/`comprehensive` are all relevance-gated, so they never pull in irrelevant content; existing callers that omit `sort_by` automatically get the better `comprehensive` default ordering.
187203
@@ -198,7 +214,13 @@ r = requests.post(f"{BASE}/reasoning/search", headers=H, json={
198214
"retrieval_mode": "hybrid",
199215
"sort_by": "comprehensive", # optional; default comprehensive; or relevance/recent/journal
200216
"format": "graph",
201-
# "filters": {"paper_ids": ["811977903947382784"], "dois": ["10.1038/s41586-021-03381-x"]}, # optional; restrict recall to papers, ≤50 each
217+
# "filters": {
218+
# "paper_ids": ["811977903947382784"],
219+
# "dois": ["10.1038/s41586-021-03381-x"],
220+
# "title": "phase stability",
221+
# "publication_date_start": "2020-01-01",
222+
# "limit_publication_date": True,
223+
# },
202224
"offset": 0,
203225
"limit": 20
204226
})
@@ -218,6 +240,9 @@ for c in data["reasoning_chains"]:
218240
| `retrieval_mode` | string | no | `hybrid`(default) / `semantic` / `lexical` |
219241
| `sort_by` | string | no | Sort strategy, same values/semantics as `/search` (`relevance`/`recent`/`journal`/`comprehensive`), default `comprehensive` when omitted |
220242
| `filters.paper_ids` / `filters.dois` | string[] | no | Restrict recall to papers, same semantics as `/search`: plain numeric IDs (no `paper:` prefix) / DOIs, ≤50 each, can be combined |
243+
| `filters.title` | string | no | Fuzzy paper-title filter; intersects (AND) with `paper_ids` and `dois` |
244+
| `filters.publication_date_start` / `filters.publication_date_end` | string | no | Publication-date bounds in `YYYY-MM-DD`; either side may be omitted |
245+
| `filters.limit_publication_date` | bool | no | Default `true`; if both bounds are omitted, fall back to approximately the last 20 years. `false` removes publication-date filtering and can recall undated papers. |
221246
| `format` | string | no | Recommended `graph`, returns `graph.nodes`/`graph.edges`; omit returns legacy structure |
222247
| `offset` | int | no | Page start, max 10000 |
223248
| `limit` | int | no | Page size, default 20, max 100 |
@@ -234,6 +259,8 @@ for c in data["reasoning_chains"]:
234259
| `data.reasoning_chains[].addressed_problems` / `open_questions` | Problems addressed / open questions |
235260
| `data.total` | Total hits; pagination: more pages if `offset + page count < total` |
236261

262+
`paper_ids`, `dois`, and `title` filters are intersected (AND), as in `/search`; an empty match in any dimension yields an empty result set.
263+
237264
---
238265

239266
## 3. Paper-level knowledge graph — `POST /papers/graph`
@@ -426,6 +453,7 @@ res = lkm_data(requests.post(f"{BASE}/search", headers=H, json={
426453
"keywords": ["FAPbI3", "thermal stability"],
427454
"retrieval_mode": "hybrid",
428455
"reasoning_only": True,
456+
"scopes": ["conclusion"],
429457
"limit": 10,
430458
}))
431459

@@ -457,7 +485,7 @@ BASE="https://open.bohrium.com/openapi/v1/lkm"
457485
# POST example (other POST endpoints work the same: just change path and body)
458486
curl -s -X POST "$BASE/search" \
459487
-H "Authorization: Bearer $AK" -H "Content-Type: application/json" \
460-
-d '{"query":"perovskite thermal stability","retrieval_mode":"hybrid","limit":20}' | jq .
488+
-d '{"query":"perovskite thermal stability","retrieval_mode":"hybrid","scopes":["abstract","conclusion"],"filters":{"title":"perovskite","publication_date_start":"2020-01-01"},"limit":20}' | jq .
461489

462490
# GET example (single-claim reasoning chain)
463491
curl -s -X GET "$BASE/claims/gcn_73e13bb548f847bd/reasoning?format=graph&max_chains=10" \
@@ -471,7 +499,7 @@ curl -s -X GET "$BASE/claims/gcn_73e13bb548f847bd/reasoning?format=graph&max_cha
471499
| code | Meaning | Fix |
472500
|------|---------|-----|
473501
| `2000` | Unauthorized | Check `BOHR_ACCESS_KEY` validity and that the request carries `Authorization: Bearer` |
474-
| `290002` | Invalid params | Check `retrieval_mode`/`scopes` values, `keywords` over limit, pagination bounds, `reasoning_only` vs scopes/role conflict, empty/over-100 `ids`, `package_id` format |
502+
| `290002` | Invalid params | Check `retrieval_mode`/`scopes` values, `keywords` over limit, pagination bounds, `reasoning_only` vs scopes/role conflict, title/date filter format, empty/over-100 `ids`, `package_id` format |
475503
| `290001` | Search/query failed | Retry once; if still failing, shorten query or lower limit |
476504
| `290004` | Claim not found | Ensure you pass a global `gcn_...`, not a graph local node ID |
477505
| `290008` | Claim has no reasoning chain | Only call reasoning on conclusions with `has_reasoning=true` |

tests/VERIFICATION_REPORT.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -321,13 +321,14 @@
321321

322322
| 端点 | 方法 | 状态 | 备注 |
323323
|------|------|------|------|
324-
| `/v2/lkm/search` | POST || 知识图谱搜索正常 |
325-
| `/v2/lkm/claims/match` | POST || 论断匹配正常 |
326-
| `/v2/lkm/claims/{id}/evidence` | GET || 证据链详情正常 |
327-
| `/v2/lkm/variables/batch` | POST || 批量查询正常 |
328-
| `/v2/lkm/papers/ocr/batch` | POST || 290007 权限不足(需更高权限 AK) |
324+
| `/v1/lkm/search` | POST || 公开检索:claim/question/abstract 命中,支持 conclusion/premise scope、title/DOI/paper/date 过滤,默认按 paper 聚合 |
325+
| `/v1/lkm/reasoning/search` | POST || 推理链检索:支持 paper_ids/dois/title/date 过滤,推荐 `format=graph` |
326+
| `/v1/lkm/claims/{id}/reasoning` | GET || 单 claim 推理链,替代旧 `/evidence` 路径 |
327+
| `/v1/lkm/papers/graph` | POST || 论文级知识图谱,按 package_id/paper_id/doi/title 查询 |
328+
| `/v1/lkm/variables/batch` | POST || 批量水合节点详情 |
329+
| `/v1/lkm/feedback` | POST || 反馈提交;写入接口,不返回知识内容 |
329330

330-
**结论**: 核心功能(搜索/匹配/证据/变量)正常;OCR 批处理需更高权限
331+
**结论**: LKM 当前 skill 以 `/openapi/v1/lkm` 为准;旧 `/v2/lkm/claims/match``/claims/{id}/evidence``/papers/ocr/batch` 不是当前 skill 推荐路径
331332

332333
---
333334

@@ -367,8 +368,8 @@
367368
| 1 | bohrium-job | API `POST /job/submit``GET /job_group/list` 返回 404 | 不影响 | CLI 正常,文档已说明优先 CLI |
368369
| 2 | bohrium-node | API `/node/start/{id}` 返回 404 || 文档使用 `restart`;start 网关无路由 |
369370
| 3 | ~~bohrium-dataset~~ | ~~`open.bohrium.com``POST /ds/` 307→404~~ | ~~~~ | **已修复**:307 已修复,统一 open.bohrium.com |
370-
| 4 | ~~bohrium-sciencepedia~~ | ~~article 端点返回 250002 "Article not found"~~ | ~~~~ | **已澄清**:用正确 `entry_id` 可正常取全文(2026-06-26 实测);250002 仅为无内容个例 |
371-
| 5 | bohrium-lkm | `/papers/ocr/batch` 返回 290007 权限不足 | | 需更高权限 AK |
371+
| 4 | bohrium-wiki | article 端点返回 250002 "Article not found" | | 索引存在,文章内容按需生成 |
372+
| 5 | ~~bohrium-lkm~~ | ~~`/papers/ocr/batch` 权限问题~~ | ~~~~ | **已更新**:当前 skill 改用 `/openapi/v1/lkm` 的 search / reasoning / graph / feedback 路径,不再推荐 OCR 批处理 |
372373

373374
## CLI 环境配置说明
374375

0 commit comments

Comments
 (0)