Skip to content

Commit 68e2bd7

Browse files
authored
watsonx.ai generation snippet (#83)
* watsonx.ai generation snippet * chore; cleanup * fix headers * fix headers
1 parent f65f6e2 commit 68e2bd7

File tree

9 files changed

+243
-3
lines changed

9 files changed

+243
-3
lines changed

ai/README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
# AI related snippets
22

3-
# MCP
3+
## MCP
44

55
Every API Connect for GraphQL deployed schema has an MCP `/mcp` endpoint
66
in addition to its `/graphql` endpoint.
77

8-
Articles:
8+
### Articles
99

1010
- https://developer.ibm.com/articles/awb-simplifying-llm-integration-mcp-api-connect-graphql/
1111
- https://community.ibm.com/community/user/blogs/timil-titus/2025/10/12/mcp-and-ibm-api-connect-for-graphql
1212

13-
Snippets:
13+
### Snippets
1414

1515
- [Prescribed tools](../executable/prescribed/) - Demonstrates creation of MCP tools from persisted GraphQL operations.
16+
17+
## AI snippets
18+
19+
- [watsonx.AI generation](watsonxai-generation/) - Demonstrates invoking an LLM through watsonx.AI within a GraphQL endpoint.

ai/watsonxai-generation/README.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# watsonx.ai generation.
2+
3+
## Overview
4+
5+
Creates a field `Query.wxai_generation` that invokes a watsonx.ai generation endpoint to infer the next text from an input.
6+
7+
This provides a simple example of calling an LLM from a GraphQL endpoint.
8+
9+
An IBM Cloud IAM token is used for authorization, taken from the [ibm-iam snippet](../../rest/ibm-iam/).
10+
11+
## Try it out
12+
13+
### Deploying
14+
15+
Deploy the schema with this values set in `.env` for your watsonx.ai project.
16+
17+
```
18+
STEPZEN_IBM_IAM_APIKEY=
19+
STEPZEN_WATSONXAI_URL=
20+
STEPZEN_WATSONXAI_PROJECTID=
21+
```
22+
23+
These can be obtained from the watsonx dashboard:
24+
25+
<img width="362" height="452" alt="image" src="https://github.com/user-attachments/assets/1eaa1671-2e2c-4a34-8ae7-1fd42ce9887e" />
26+
27+
### Sample request
28+
29+
Then you can use `stepzen request` and the provided operation to ask simple questions:
30+
31+
```
32+
stepzen request --file op.graphql --var question="when was hadrian's wall built"
33+
```
34+
35+
recieving a GraphQL response like:
36+
37+
```
38+
{
39+
"data": {
40+
"wxai_generation": {
41+
"created_at": "2025-11-12T18:29:23.65Z",
42+
"model_id": "ibm/granite-3-8b-instruct",
43+
"model_version": "1.1.0",
44+
"results": [
45+
{
46+
"generated_text": "\n\nHadrian's Wall was built between 122 and 128 AD",
47+
"generated_token_count": 20,
48+
"input_token_count": 7,
49+
"stop_reason": "max_tokens"
50+
}
51+
]
52+
}
53+
}
54+
}
55+
```
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
configurationset:
2+
- configuration:
3+
name: ibm-iam
4+
endpoint: https://iam.cloud.ibm.com/identity/token
5+
apikey: STEPZEN_IBM_IAM_APIKEY
6+
- configuration:
7+
name: watsonx-service
8+
version: '2024-06-28'
9+
url: STEPZEN_WATSONXAI_URL
10+
project_id: STEPZEN_WATSONXAI_PROJECTID
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
extend type Query {
2+
"""
3+
Obtain an IBM Cloud bearer token.
4+
5+
Uses the [IBM Cloud API Key](https://cloud.ibm.com/docs/account?topic=account-userapikey&interface=ui#userapikey)
6+
or [service ID's API Key](https://cloud.ibm.com/docs/account?topic=account-serviceidapikeys&interface=ui)
7+
to [generate an IAM Token](https://cloud.ibm.com/docs/account?topic=account-iamtoken_from_apikey#iamtoken_from_apikey)
8+
"""
9+
ibm_iam_token: Secret
10+
@rest(
11+
endpoint: "$endpoint"
12+
method: POST
13+
contenttype: "x-www-form-urlencoded"
14+
postbody: """
15+
grant_type=urn:ibm:params:oauth:grant-type:apikey&apikey={{ .Get "apikey"}}
16+
"""
17+
ecmascript: """
18+
function transformREST(body) {
19+
switch (status) {
20+
case 200:
21+
return body
22+
case 401:
23+
case 400: // returned for apikey not found
24+
throw new Error('unauthorized');
25+
default:
26+
throw new Error('unknown error');
27+
}
28+
}
29+
"""
30+
setters: { path: "access_token" }
31+
configuration: "ibm-iam"
32+
)
33+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
"""
2+
Snippet demonstrating calling Watsonx.AI's generation endpoint.
3+
"""
4+
schema
5+
@sdl(
6+
files: ["watsonx-ai.graphql", "ibm-iam.graphql"]
7+
# Only expose wxai_ fields
8+
visibility: { expose: true, types: "Query", fields: "wxai_.*" }
9+
# ensure the operation remains valid
10+
executables: { document: "op.graphql" }
11+
) {
12+
query: Query
13+
}

ai/watsonxai-generation/op.graphql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
query AskWatsonxAI($question: String!) {
2+
wxai_generation(input: $question) {
3+
created_at
4+
model_id
5+
model_version
6+
results {
7+
generated_text
8+
generated_token_count
9+
input_token_count
10+
stop_reason
11+
}
12+
}
13+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"endpoint": "api/miscellaneous"
3+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const {
2+
deployAndRun,
3+
getTestDescription,
4+
} = require("../../../tests/gqltest.js");
5+
6+
testDescription = getTestDescription("snippets", __dirname);
7+
8+
describe(testDescription, function () {
9+
const tests = [];
10+
return deployAndRun(__dirname, tests);
11+
});
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
extend type Query {
2+
"""
3+
Infers the next tokens for a given deployed model from the `input` text.
4+
"""
5+
wxai_generation(
6+
input: String
7+
model_id: String! = "ibm/granite-3-8b-instruct"
8+
parameters: WXAI_GenerationParameters
9+
): WXAI_GenerationResponse
10+
@sequence(
11+
steps: [
12+
{ query: "ibm_iam_token" }
13+
{
14+
query: "_wxai_generation"
15+
arguments: [
16+
{ name: "token", field: "§0" }
17+
{ name: "input", argument: "input" }
18+
{ name: "model_id", argument: "model_id" }
19+
{ name: "parameters", argument: "parameters" }
20+
]
21+
}
22+
]
23+
)
24+
25+
"""
26+
Calls the generation endpoint.
27+
"""
28+
_wxai_generation(
29+
token: Secret!
30+
input: String
31+
model_id: String
32+
parameters: WXAI_GenerationParameters
33+
): WXAI_GenerationResponse
34+
@rest(
35+
method: POST
36+
endpoint: "$url;"
37+
path: "/ml/v1/text/generation?version=$version"
38+
headers: [{ name: "authorization", value: "Bearer $token" }]
39+
ecmascript: """
40+
function bodyPOST(s) {
41+
let body = JSON.parse(s)
42+
body.project_id = get("project_id")
43+
return JSON.stringify(body)
44+
}
45+
"""
46+
configuration: "watsonx-service"
47+
)
48+
}
49+
50+
"""
51+
The parameters for the model of a generative AI request. See https://cloud.ibm.com/apidocs/watsonx-ai#text-generation for more details.
52+
"""
53+
input WXAI_GenerationParameters {
54+
"""
55+
The temperature specifies the amount of variation in the generation process when using sampling mode.
56+
"""
57+
temperature: Float = 0
58+
"""
59+
The strategy the model uses to choose the tokens in the generated output.
60+
"""
61+
decoding_method: String
62+
"""
63+
The minimum number of new tokens to be generated.
64+
"""
65+
min_new_tokens: Int
66+
"""
67+
The maximum number of new tokens to be generated.
68+
"""
69+
max_new_tokens: Int = 20
70+
"""
71+
The repetition penalty lowers the probability scores of tokens that have already been generated or belong to the context.
72+
"""
73+
repetition_penalty: Float
74+
"""
75+
A string of one or more characters which will stop the text generation if/when they appear in the generated output.
76+
"""
77+
stop_sequences: [String]
78+
}
79+
80+
"""
81+
Response of IBM watsonx.ai `generation` endpoint
82+
"""
83+
type WXAI_GenerationResponse {
84+
created_at: DateTime
85+
model_id: String
86+
model_version: String
87+
results: [WXAI_GenerationResult]
88+
}
89+
90+
"""
91+
A result in the response of IBM watsonx.ai `generation` endpoint
92+
"""
93+
type WXAI_GenerationResult {
94+
generated_text: String
95+
generated_token_count: Int
96+
input_token_count: Int
97+
stop_reason: String
98+
}

0 commit comments

Comments
 (0)